home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / program / oxcc1434.zip / SRC / OXCCL.C < prev    next >
C/C++ Source or Header  |  1996-09-03  |  82KB  |  3,714 lines

  1. /*
  2.     oxccl.c -- v1.430 architecture neutral format (anf) linker
  3.  
  4.     Copyright (c) 1995
  5.     Norman D. Culver dba
  6.     Oxbow Software
  7.     1323 S.E. 17th Street #662
  8.     Ft. Lauderdale, FL 33316
  9.     (954) 463-4754
  10.     ndc@icanect.net
  11.     All rights reserved.
  12.  
  13.  * Redistribution and use in source and binary forms are permitted
  14.  * provided that: (1) source distributions retain this entire copyright
  15.  * notice and comment, and (2) distributions including binaries display
  16.  * the following acknowledgement:  ``This product includes software
  17.  * developed by Norman D. Culver dba Oxbow Software''
  18.  * in the documentation or other materials provided with the distribution
  19.  * and in all advertising materials mentioning features or use of this
  20.  * software.
  21.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  22.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  23.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  
  25. */
  26. #define MAJOR_VERSION 1
  27. #define MINOR_VERSION 433
  28.  
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <stdio.h>
  32. #include <setjmp.h>
  33.  
  34. #define NEED_FUNCTHUNK 1
  35. #define NEED_ANFDEFS 1
  36. #include "oxanf.h"
  37.  
  38. #define PROG oxccl
  39. #define USING_FRAMEWORK 1
  40. #define HOST_IS_LITTLE_ENDIAN 1
  41. #define REALLY_NEED_OFFSETS 0
  42.  
  43. #define PRINTF printf
  44. #define VFPRINTF(a,b) vfprintf(stderr,a,b)
  45. #define PERROR prerror
  46. #define PWARN prwarn
  47. static void prerror(const char*, ...);
  48. static void prwarn(const char*, ...);
  49.  
  50. #define FILEWRITE(buf, cnt)\
  51. {if(!iv->errors){if(fwrite(buf, 1, cnt, iv->outfile) != cnt)iv->errors = 12;}}
  52. #define ROUNDING(a,b) ((a+(b-1))&~(b-1))
  53. #define ROUNDUP(a,b) a += ROUNDING(a,b)
  54.  
  55. /* ======================== CONCATENIZATION MACROS ==================== */
  56.  
  57. #define    _cat2_(a, b)    a##b
  58. #define _cat_(a, b)    _cat2_(a, b)
  59. #define Global(a) _cat_(PROG, a)
  60.  
  61. #define _pname2_(x)    #x
  62. #define _pname1_(x)    _pname2_(x)
  63. #define pName        _pname1_(PROG)
  64.  
  65.  
  66. /* ============== ENDIAN MACROS (input format is litle endian) ==== */
  67.  
  68. #if HOST_IS_LITTLE_ENDIAN
  69. #define GL(a) a
  70. #define GS(a) a
  71. #define PL(a) a
  72. #define PS(a) a
  73. #else
  74. #endif
  75.  
  76. /* =================== INPUT DATA FORMATS ========================== */
  77.  
  78. #define INFILE_SYMNUM 1
  79. #define OUTFILE_SYMNUM 2
  80.  
  81.  
  82. /* ====================== STRUCTURES AND TYPEDEFS ======================== */
  83.  
  84. typedef struct _jl {
  85.     struct _jl *next;
  86.     void *p;
  87.     char *q;
  88.     long *plabelval;
  89.     long offset;
  90. } *PJL;
  91.  
  92. typedef struct _afile {
  93.     unsigned char *file_p;
  94.     PopI header_p;
  95.     PopI size_p;
  96.     unsigned char *symtext_p;
  97.     unsigned char *prog_p;
  98.     unsigned char *data_p;
  99.     unsigned char *switch_p;
  100.     unsigned char *decl_p;
  101.     unsigned char *maxtemp_p;
  102.     unsigned char *seg_p;
  103.     unsigned char **symaddr;
  104.     unsigned char **decladdr;
  105.     unsigned long thunk_offset;
  106.     unsigned long bss_offset;
  107.     int maxtemp;
  108.     int maxtempclass;
  109.     void *datatbl;
  110.     short *symtran;
  111.     unsigned short *decltran;
  112.     int filenum;
  113.     int numsyms;
  114.     int numdecls;
  115.     int numrelocs;
  116.     int numsegs;
  117. } *Pafile;
  118.  
  119. typedef struct _iv {
  120.     int category;
  121.     FILE *outfile;
  122.     int remove_infile;
  123.     int argc;
  124.     char **argv;
  125.     unsigned char **symaddr;
  126.     unsigned char **decladdr;
  127.     int numfiles;
  128.     int lastlabel;
  129.     int errors;
  130.     int numsyms;
  131.     int numdecls;
  132.     int numsegs;
  133.     int maxtemp;
  134.     int maxtempclass;
  135.     unsigned long total_size;
  136.     unsigned long thunk_offset;
  137.     unsigned long bss_offset;
  138.     long first_temp;
  139.     long killop;
  140.     void *reloctbl;
  141.     void *extrntbl;
  142.     void *gbltbl;
  143.     void *symtbl;
  144.     void *labeltbl;
  145.     void *newlabeltbl;
  146.     void *tmptbl;
  147.     void *segtbl;
  148.     int temps_written;
  149.     unsigned char *obuf;
  150.     unsigned char *obufstart;
  151.     PJL jbuf;
  152.     void *jbufstart;
  153.     int jmpcnt;
  154.     int jbufcnt;
  155.     long obufcnt;
  156.     long out_offset;
  157.     long func_offset;
  158.     int filenum;
  159.     Pafile files[1024];
  160.     char debug;
  161.     char only_debug;
  162.     char strip;
  163. } *Piv;
  164.  
  165. struct _gloval {
  166.     char *symname;
  167.     unsigned char *p;
  168.     Pafile pf;
  169.     int symnum;
  170. };
  171.  
  172.  
  173. /* Internal User API */
  174. static void *Cmalloc(int category, unsigned amount);
  175. static void *Ccalloc(int category, unsigned nelems, unsigned elemsize);
  176. static void *Crealloc(int category, void* buf, unsigned newsize);
  177. static void Cfree(int category, void* buf);
  178. static void Cfreecat(int category);
  179. static int Cmemrange(int category, unsigned* minp, unsigned* maxp);
  180. static int Cusedrange(int category, unsigned* minp, unsigned* maxp);
  181. static void Ctotrange(unsigned* minp,unsigned* maxp);
  182. static int Cnewcat(void);
  183. static void Cguard(int category);
  184. static void* NewSymTable(int category, int nbins);
  185. static int SymFind(void *tbl, void *key, void *result);
  186. static int SymFindRange(void *tbl, void *key, void *result);
  187. static void *SymInsert(void *tbl, void *key, void *value, int datsiz);
  188. static int StringInsert(void *tbl, char *string, void *result);
  189. static int StringFind(void *tbl, char *string, void *result);
  190. static void SymDelete(void *tbl, void *key);
  191. static int SymHead(void *tbl);
  192. static int SymNext(void *tbl);
  193. static void SymGetMark(void *tbl, void *markptr);
  194. static int SymMarkNext(void *tbl, void *mark);
  195. static void SymSetMark(void *tbl, void *markptr);
  196. static void SymKey(void *tbl, void *keyptr);
  197. static void SymValue(void *tbl, void *datptr);
  198. static void *seg_find(Piv iv, int id);
  199. static char *filenameof(char *path);
  200. static char *propernameof(Piv iv, char *name);
  201.  
  202. /* END: User API */
  203.  
  204. /* ====================== PUT UNIQUE CODE HERE ========================= */
  205. /* ===================== LINKER OUTPUT GENERATOR ======================= */
  206. static void
  207. gen_infop3(Piv iv, int op, long a, long b, long c)
  208. {
  209. struct {
  210.     unsigned char op[2];
  211.     short pad;
  212.     long next;
  213.     long a;
  214.     long b;
  215.     long c;
  216. }immed;
  217.  
  218.     immed.op[0] = op;
  219.     immed.op[1] = OPIMMED3|12;
  220.     immed.pad = 0;
  221.     immed.next = sizeof(immed);
  222.     immed.a = a;
  223.     immed.b = b;
  224.     immed.c = c;
  225.     FILEWRITE(&immed, sizeof(immed))
  226. }
  227. static void
  228. gen_infop1(Piv iv, int op, long a)
  229. {
  230. struct {
  231.     unsigned char op[2];
  232.     short pad;
  233.     long next;
  234.     long a;
  235. }immed;
  236.  
  237.     immed.op[0] = op;
  238.     immed.op[1] = OPIMMED1|4;
  239.     immed.pad = 0;
  240.     immed.next = sizeof(immed);
  241.     immed.a = a;
  242.     FILEWRITE(&immed, sizeof(immed))
  243. }
  244. static void
  245. gen_infop0(Piv iv, int op)
  246. {
  247. struct {
  248.     unsigned char op[2];
  249.     short pad;
  250.     long next;
  251. }immed;
  252.  
  253.     immed.op[0] = op;
  254.     immed.op[1] = 0;
  255.     immed.pad = 0;
  256.     immed.next = sizeof(immed);
  257.     FILEWRITE(&immed, sizeof(immed))
  258. }
  259.  
  260. static void
  261. dump_header(Piv iv)
  262. {
  263. Pafile pf;
  264. unsigned char *p, *next;
  265.     pf = iv->files[0];
  266.     p = pf->file_p;
  267.     next = POP->next;
  268.     PL(POP->next) = (void*)20;        /* unlink node */
  269.     FILEWRITE(p, 20)
  270.     PL(POP->next) = next;    /* relink node */
  271.     gen_infop3(iv, dataop, iv->total_size, iv->thunk_offset, iv->bss_offset);
  272. }
  273. static void
  274. dump_symbols(Piv iv)
  275. {
  276. extern void *Cmalloc();
  277. int sym_offset = 0;
  278. int pad;
  279. int i;
  280. int *symlens = Cmalloc(iv->category, sizeof(int)*iv->numsyms);
  281.  
  282.     /* Symbol Count */
  283.     gen_infop1(iv, symbop, iv->numsyms);
  284.     /* Symbol offsets */
  285.     for(i = 0; i < iv->numsyms; ++i)
  286.     {
  287.         gen_infop1(iv, symoffsetop, sym_offset);
  288.         symlens[i] = strlen(iv->symaddr[i])+1;
  289.         sym_offset += symlens[i];
  290.     }
  291.  
  292.     /* Contiguous block of symbol strings */
  293.     gen_infop1(iv, symblockop,sym_offset);    
  294.     for(i = 0; i < iv->numsyms; ++i) {
  295.         FILEWRITE(iv->symaddr[i], symlens[i])
  296.     }
  297.  
  298.     /* Alignment is 4 bytes */
  299.     pad = (4-(sym_offset&3))&3;
  300.     if(pad == 1)
  301.         FILEWRITE("", 1)
  302.     else if(pad == 2)
  303.         FILEWRITE(" ", 2)
  304.     else if(pad == 3)
  305.         FILEWRITE("  ", 3)
  306. }
  307. static void
  308. dump_files(Piv iv)
  309. {
  310. Pafile pf;
  311. unsigned char *p, *next;
  312. int i, dsize;
  313.  
  314.     /* Output could be neatened up by collecting various subgroups
  315.         but it would require several passes over the files */
  316.     
  317.     for(i = 0; i < iv->numfiles; ++i)
  318.     {
  319.         pf = iv->files[i];
  320.         p = pf->file_p;
  321.         while(*p != endfileop)
  322.         {
  323.             next = POP->next;
  324.             dsize = 0;
  325.  
  326.             switch(*p)
  327.             {
  328.                 case    0:
  329.                 case    headerop:
  330.                 case    dataop:
  331.                 case    symoffsetop:
  332.                 case    symblockop:
  333.                 case    symbop:
  334.                     break;
  335.                 case    stringblockop:
  336.                 case    datablockop:
  337.                 case    mallocblockop:
  338.                 case    thunkblockop:
  339.                     dsize = GL(POP->data);
  340.                     dsize += ((4-(dsize&3))&3); /* alignment */
  341.                 /* FALL THROUGH */
  342.                 default:
  343.                 {
  344.                 size_t size = next - p;
  345.                     PL(POP->next) = (void*)(size - dsize);    /* unlink node */
  346.                     FILEWRITE(p, size)
  347.                     break;
  348.                 }
  349.             }
  350.             p = next;
  351.         }
  352.     }
  353. }
  354. static void
  355. dump_trailer(Piv iv)
  356. {
  357.     gen_infop0(iv, endfileop);
  358.     gen_infop0(iv, endallop);
  359. }
  360.  
  361. static int
  362. gen_output(Piv iv, char *outpath)
  363. {/* Linker output */
  364. char *cp;
  365. int i;
  366. char outname[256];
  367.  
  368.     strcpy(outname, outpath);
  369.     if((cp = strrchr(outname, '.')))
  370.     {
  371. #if 0
  372.         strcpy(cp, ".anf");
  373. #endif
  374.     }
  375.     else
  376.     {
  377.         strcat(outname, ".anf");
  378.     }
  379.     for(i = 1; i < iv->argc; ++i)
  380.     {
  381.       if(!strcmp(outname, iv->argv[i]))
  382.       {
  383.         PERROR(pName ":ERROR output file `%s' is same as input file\n", outname);
  384.       }
  385.     }
  386.     if(!(iv->outfile = fopen(outname, "wb")))
  387.     {
  388.         PERROR(pName ":ERROR: Cannot open output file %s\n", outname);
  389.     }
  390.     dump_header(iv);
  391.     dump_symbols(iv);
  392.     dump_files(iv);
  393.     dump_trailer(iv);
  394.     fclose(iv->outfile);
  395.     iv->outfile = 0;    
  396.     return iv->errors;
  397. }
  398. /* ======================= END LINKER OUTPUT GENERATOR ==================== */
  399.  
  400. /* ===================== GENERIC CODE BELOW THIS POINT ================== */
  401. static jmp_buf run_env;
  402. static void
  403. prerror(const char *fmt, ...)
  404. {
  405.     VFPRINTF(fmt, (char *)(((int *)(&fmt))+1));
  406.     longjmp(run_env, 3);
  407. }
  408. static void
  409. prwarn(const char *fmt, ...)
  410. {
  411.     VFPRINTF(fmt, (char *)(((int *)(&fmt))+1));
  412. }
  413. /* ========================= MULTI HEAP MALLOC ========================== */
  414. #define LOCAL static
  415.  
  416. #if USING_FRAMEWORK
  417. #define THEWELL(a) mallocC(local_category, a)
  418. static int local_category;
  419. static int num_instance;
  420. extern void *mallocC(int, int);
  421. extern void freecat(int);
  422. extern void oxlink_clear_bss();
  423. extern int NewMallocCategory();
  424. #endif /* USING_FRAMEWORK */
  425.  
  426. #define BASE_CATEGORY 0
  427. #define MEMORY_BUG 0
  428. #define PRINT_RAWDATA 0
  429.  
  430. #if MEMORY_BUG == 1
  431. #define MPRINTF printf
  432. #else
  433. #define MPRINTF(args...)
  434. #endif
  435.  
  436. #define PAGESIZE (4096)    /* can use `pagesize' function in OS */
  437. #define ALIGNMENTM (sizeof(unsigned long))
  438. #define MAL_MAXLEVEL (12)
  439. #define ROUNDINGM(a) ((a+(ALIGNMENTM-1))&~(ALIGNMENTM-1))
  440. #define ALLOCSIZE (4096)
  441. #define FRNTGUARD (0x544e5246UL)
  442. #define BACKGUARD (0x48434142UL)
  443. #ifndef THEWELL
  444. #define THEWELL do_sbrk
  445. #endif
  446. #define NUMTYPES 3
  447. #define SIZEH 0
  448. #define FREEH 1
  449. #define USEDH 2
  450.  
  451. #define SKIPVARS NodePM update[MAL_MAXLEVEL+1];NodePM node,prev;int level
  452.  
  453. #define DELETENODE(TYPE) \
  454. {for(level=0;level<=bp->TYPE##level; level++)\
  455. {if(update[level]->fptr[level] == node)\
  456. update[level]->fptr[level] = node->fptr[level];else break;}\
  457. while(bp->TYPE##level>0 && bp->TYPE##header->fptr[bp->TYPE##level]==_NILLL)\
  458. bp->TYPE##level--;free_Mnode(bp,node,TYPE);}
  459.  
  460. #define INSERT() \
  461. {while(level >= 0){\
  462. node->fptr[level] = update[level]->fptr[level];\
  463. update[level]->fptr[level] = node;level--;}}
  464.  
  465. #define SETLEVEL(TYPE) \
  466. {level = getMlevel(bp, bp->TYPE##level);\
  467. while(bp->TYPE##level < level)update[++bp->TYPE##level]=bp->TYPE##header;}
  468.  
  469. #define FINDKEY(TYPE, KEYVAL)\
  470. {node = bp->TYPE##header;\
  471. for(level = bp->TYPE##level; level >= 0; level--){\
  472. while(node->fptr[level]->key < KEYVAL)\
  473. node = node->fptr[level];\
  474. update[level] = node;}prev=node;node=node->fptr[0];}
  475.  
  476. #define DETACH(SN)\
  477. {SN->bptr->fptr=SN->fptr;if(SN->fptr)SN->fptr->bptr=SN->bptr;}
  478.  
  479. #define UNLINK(SN, N)\
  480. {if(!sp->fptr&&sp->bptr->bptr<=(AddrP)(MAL_MAXLEVEL+1))dsize[N]=sp->size;\
  481. DETACH(SN);free_addr(bp,SN);}
  482.  
  483. #define CHECKGUARDS(MSG)\
  484. {if(bp->guarded){\
  485. unsigned *p2;\
  486. p2 = (void*)((char*)address+cursize-ALIGNMENTM);\
  487. if(*address != FRNTGUARD)\
  488. PERROR(pName #MSG ":%d: corrupted at 0x%x\n", bp->bincat, addr);\
  489. if(*p2 != BACKGUARD)\
  490. PERROR(pName #MSG ":%d: corrupted by 0x%x\n", bp->bincat, addr);}}
  491.  
  492. #if MEMORY_BUG == 1
  493. #define HEAPCHECK \
  494. {void *lastaddr;\
  495. if(category > 0){\
  496. Cguard(category);\
  497. if((lastaddr = Cheapcheck(category, NULL))){\
  498. FINDKEY(USEDH, (unsigned)lastaddr-ALIGNMENTM)\
  499. MPRINTF("bad heap at %x c:%u size=%u\n", lastaddr, category, node->value);\
  500. (void)print_rawdata(lastaddr-ALIGNMENTM, node->value);\
  501. abort();}}}
  502. #else
  503. #define HEAPCHECK
  504. #endif
  505.  
  506. struct _catlocs {
  507.     void *addr;
  508.     struct _catlocs *fptr;
  509. };
  510.  
  511. typedef struct _nodeM
  512. {
  513.     unsigned key;
  514.     unsigned value;
  515.     unsigned levels;    /* must always be after value */
  516.     struct _nodeM *fptr[1];
  517. } NodeM, *NodePM;
  518.  
  519. typedef struct _addr
  520. {
  521.     struct _addr *fptr;
  522.     struct _addr *bptr;
  523.     NodePM maddr;
  524.     unsigned size;
  525. } *AddrP;
  526.  
  527. struct _bins {
  528.     unsigned bits;
  529.     unsigned nbits;
  530.     NodePM SIZEHheader;
  531.     int SIZEHlevel;
  532.     NodePM FREEHheader;
  533.     int FREEHlevel; 
  534.     NodePM USEDHheader;
  535.     int USEDHlevel;
  536.  
  537.     unsigned bincat;
  538.     unsigned maxloc;
  539.     unsigned minloc;
  540.     struct _catlocs *catlocs;
  541.     struct _bins *fptr;
  542.     NodePM freenodes[NUMTYPES][MAL_MAXLEVEL+2];
  543.     struct _addr *freeaddrlocs;
  544.     char *chunkbase[NUMTYPES];
  545.     int chunksize[NUMTYPES];
  546.     int guarded;
  547.     int addrbump;
  548. };
  549.  
  550. static struct _bins zbp;
  551. static struct _bins *hmap[1009];
  552. static struct _nodeM _nilll = {0xffffffff,0,0,{0}};
  553. static struct _nodeM *_NILLL = &_nilll;
  554. static unsigned maxloc;
  555. static unsigned minloc;
  556. static struct _bins *freebinlocs;
  557. static struct _catlocs *freecatlocs;
  558. static char *binbase;
  559. static int binsize;
  560. static int chunksizes[] = {ALLOCSIZE,3*ALLOCSIZE,2*ALLOCSIZE};
  561.  
  562.  
  563. static long randtbl[32]    = { 0L,
  564.     0x9a319039L, 0x32d9c024L, 0x9b663182L, 0x5da1f342L, 
  565.     0xde3b81e0L, 0xdf0a6fb5L, 0xf103bc02L, 0x48f340fbL, 
  566.     0x7449e56bL, 0xbeb1dbb0L, 0xab5c5918L, 0x946554fdL, 
  567.     0x8c2e680fL, 0xeb3d799fL, 0xb11ee0b7L, 0x2d436b86L, 
  568.     0xda672e2aL, 0x1588ca88L, 0xe369735dL, 0x904f35f7L, 
  569.     0xd7158fd6L, 0x6fa6f051L, 0x616e6b96L, 0xac94efdcL, 
  570.     0x36413f93L, 0xc622c298L, 0xf5a42ab8L, 0x8a88d77bL, 
  571.     0xf5ad9d0eL, 0x8999220bL, 0x27fb47b9L
  572. };
  573.  
  574. static  long *fptr    = &randtbl[4];
  575. static  long *rptr    = &randtbl[1];
  576.  
  577. /* ======================== START OF CODE =========================== */
  578. #if PRINT_RAWDATA == 1
  579. static char
  580. hexbyte(unsigned int c)
  581. {
  582. char x = c & 0xf;
  583.  
  584.     return x + ((x>9) ? 55 : 48);
  585. }
  586. static void
  587. print_rawdata(void *rawdata, long size)
  588. {
  589. unsigned long vaddr = 0;
  590. unsigned char *d = rawdata;
  591. int i,j;
  592. char addr[9];
  593. char hex1[24];
  594. char hex2[24];
  595. char side1[9];
  596. char side2[9];
  597.  
  598.     addr[8] = 0;
  599.     hex1[23] = 0;
  600.     hex2[23] = 0;
  601.     side1[8] = 0;
  602.     side2[8] = 0;
  603.     while(size > 0)
  604.     {
  605.     unsigned long qaddr = vaddr;
  606.         memset(addr, '0', 8);
  607.         memset(hex1, ' ', 23);
  608.         memset(hex2, ' ', 23);
  609.         memset(side1, ' ', 8);
  610.         memset(side2, ' ', 8);
  611.         i = 7;
  612.         while(qaddr)
  613.         {
  614.             addr[i--] = hexbyte(qaddr);
  615.             qaddr >>= 4;
  616.         }
  617.         for(i=0,j=0; i < 8; ++i)
  618.         {
  619.             if(--size >= 0)
  620.             {
  621.             unsigned int c = *d++;
  622.                 if(isprint(c))
  623.                     side1[i] = c;
  624.                 else
  625.                     side1[i] = '.';
  626.                 hex1[j++] = hexbyte(c>>4);
  627.                 hex1[j++] = hexbyte(c);
  628.                     ++j;
  629.             }
  630.             else break;
  631.         }
  632.         for(i=0,j=0; i < 8; ++i)
  633.         {
  634.             if(--size >= 0)
  635.             {
  636.             unsigned int c = *d++;
  637.                 if(isprint(c))
  638.                     side2[i] = c;                    
  639.                 else
  640.                     side2[i] = '.';
  641.                 hex2[j++] = hexbyte(c>>4);
  642.                 hex2[j++] = hexbyte(c);
  643.                 ++j;
  644.             }
  645.             else break;
  646.         }
  647.         VPRINTF("%s  %s%s%s  %s%s%s\n",addr,hex1," | ",hex2,side1,"|",side2);
  648.         vaddr += 16;
  649.     }
  650. }
  651. #endif
  652.  
  653. /*
  654.  * Returns a really good 31-bit random number.
  655.  */
  656. static long
  657. lrandom()
  658. {
  659. long i;
  660.     
  661.     *fptr += *rptr;
  662.     i = (*fptr >> 1) & 0x7fffffffUL;
  663.     if(++fptr > &randtbl[31])
  664.     {
  665.         fptr = &randtbl[1];
  666.         ++rptr;
  667.     }
  668.     else
  669.     {
  670.         if(++rptr > &randtbl[31])  
  671.             rptr = &randtbl[1];
  672.     }
  673.     return( i );
  674. }
  675. #if !USING_FRAMEWORK
  676. static void *
  677. do_sbrk(unsigned amount)
  678. {
  679. void *address;
  680.  
  681.     address = sbrk(amount);    /* OR WHATEVER TO ACCESS THE OPERATING SYSTEM */
  682.     if(address == (void*)-1)
  683.     {
  684.         PERROR(pName "\nsystem out of memory, requested %u bytes\n", amount);
  685.     }
  686.     return address;
  687. }
  688. #endif
  689.  
  690. static struct _catlocs *
  691. new_catloc(void)
  692. {
  693. struct _catlocs *p;
  694.     if((p=freecatlocs))
  695.     {
  696.         freecatlocs = p->fptr;
  697.         return p;
  698.     }
  699.     if(binsize < sizeof(struct _catlocs))
  700.     {
  701.         binbase = THEWELL(4096);
  702.         binsize = 4096;
  703.     }
  704.     binsize -= sizeof(struct _catlocs);
  705.     p = (void*)binbase;
  706.     binbase += sizeof(struct _catlocs);
  707.     return p;
  708. }
  709. static void
  710. free_catloc(struct _catlocs *p)
  711. {
  712.     p->fptr = freecatlocs;
  713.     freecatlocs = p;
  714. }
  715. static void *
  716. new_chunk(struct _bins *bp, int size, int type)
  717. {
  718. char *p;
  719.      if(bp->chunksize[type] < size)
  720.     {
  721.         if(bp->bincat == 0) {
  722.             bp->chunkbase[type] = THEWELL(chunksizes[type]);
  723.             bp->chunksize[type] = chunksizes[type];
  724.         }
  725.         else {
  726.         struct _catlocs *cl;
  727.             bp->chunkbase[type] = Cmalloc(0,chunksizes[type]-zbp.guarded);
  728.             bp->chunksize[type] = chunksizes[type]-zbp.guarded;
  729.             cl = new_catloc();
  730.             cl->addr = bp->chunkbase[type];
  731.             cl->fptr = bp->catlocs;
  732.             bp->catlocs = cl;
  733.         }
  734.     }
  735.     bp->chunksize[type] -= size;
  736.     p = bp->chunkbase[type];
  737.     bp->chunkbase[type] += size;
  738.     return p;
  739. }
  740. static void *
  741. new_Mnode(struct _bins *bp, int levels, int type)
  742. {
  743. int size;
  744. NodePM p;
  745.  
  746.     if((p=bp->freenodes[type][levels]))
  747.     {
  748.         bp->freenodes[type][levels] = p->fptr[0];
  749.         p->value = 0;
  750.         return p;
  751.     }
  752.      size = sizeof(struct _nodeM) + levels * sizeof(void*);
  753.     p = new_chunk(bp, size, type);
  754.     p->levels = levels;
  755.     p->value = 0;
  756.     return p;    
  757. }
  758. static void
  759. free_Mnode(struct _bins *bp, NodePM p, int type)
  760. {
  761.     p->fptr[0] = bp->freenodes[type][p->levels];
  762.     bp->freenodes[type][p->levels] = p;
  763. }
  764. static struct _addr *
  765. new_addr(struct _bins *bp)
  766. {
  767. struct _addr *p;
  768.     if((p=bp->freeaddrlocs))
  769.     {
  770.         bp->freeaddrlocs = p->fptr;
  771.         return p;
  772.     }
  773.     return new_chunk(bp, sizeof(struct _addr), FREEH);
  774. }
  775. static void
  776. free_addr(struct _bins *bp, struct _addr *p)
  777. {
  778.     p->fptr = bp->freeaddrlocs;
  779.     bp->freeaddrlocs = p;
  780. }
  781. static struct _bins *
  782. new_bins(void)
  783. {
  784. struct _bins *p;
  785.     if((p=freebinlocs))
  786.     {
  787.         freebinlocs = p->fptr;
  788.         return p;
  789.     }
  790.      if(binsize < sizeof(struct _bins))
  791.     {
  792.         binbase = THEWELL(4096);
  793.         binsize = 4096;
  794.     }
  795.     binsize -= sizeof(struct _bins);
  796.     p = (struct _bins*)binbase;
  797.     binbase += sizeof(struct _bins);
  798.     return p;
  799. }
  800. static void
  801. free_bins(struct _bins *p)
  802. {
  803.     p->fptr = freebinlocs;
  804.     freebinlocs = p;
  805. }
  806. static int
  807. getMlevel (struct _bins *p, int binlevel)
  808. {
  809. int level = -1;
  810. int bits = 0;
  811.  
  812.     while(bits == 0)
  813.     {
  814.         if (p->nbits == 0)
  815.         {
  816.             p->bits = lrandom();
  817.             p->nbits = 15;
  818.         }
  819.         bits = p->bits & 3;
  820.         p->bits >>= 2;
  821.         p->nbits--;
  822.  
  823.         if(++level > binlevel)
  824.             break;
  825.     }
  826.     return (level > MAL_MAXLEVEL) ? MAL_MAXLEVEL : level;
  827. }
  828.  
  829. static void
  830. init_bins(struct _bins *bp, int category)
  831. {
  832. int i;
  833. int binnum = category % 1009;
  834.  
  835.     bzero(bp, sizeof(struct _bins));
  836.     bp->bincat = category;
  837.     bp->minloc = 0xffffffff;
  838.     bp->fptr = hmap[binnum];
  839.     hmap[binnum] = bp;
  840.     bp->SIZEHheader = new_Mnode(bp, MAL_MAXLEVEL+1, SIZEH);
  841.     bp->FREEHheader = new_Mnode(bp, MAL_MAXLEVEL+1, FREEH);
  842.     bp->USEDHheader = new_Mnode(bp, MAL_MAXLEVEL+1, USEDH);
  843.  
  844.     for(i = 0; i <= MAL_MAXLEVEL; ++i)
  845.     {
  846.         bp->SIZEHheader->fptr[i] = _NILLL;
  847.         bp->FREEHheader->fptr[i] = _NILLL;
  848.         bp->USEDHheader->fptr[i] = _NILLL;
  849.     }
  850. }
  851.  
  852. static struct _bins*
  853. getcat(int category)
  854. {
  855. struct _bins *hbp;
  856.  
  857.     hbp = hmap[category % 1009];
  858.     while(hbp)
  859.     {
  860.         if(hbp->bincat == category)
  861.             return hbp;
  862.         hbp = hbp->fptr;
  863.     }
  864.     return 0;
  865. }
  866. static struct _bins *
  867. initcat(int category)
  868. {
  869. struct _bins *bp;
  870.  
  871.     if(category == 0)
  872.     {
  873.         bp = &zbp;
  874.         if(zbp.SIZEHheader == 0)
  875.             init_bins(bp, category);
  876.         return bp;
  877.     }
  878.     /* do this to set zbp.guarded properly on startup */
  879.     if(zbp.SIZEHheader == 0)
  880.         initcat(0);
  881.  
  882.     if((bp = new_bins()))
  883.     {
  884.         init_bins(bp, category);
  885.         return bp;
  886.     }
  887.     return 0;
  888. }
  889. static void *
  890. getspace(struct _bins *bp, unsigned size, unsigned *remainder)
  891. {
  892. unsigned desired;
  893. void *address;
  894.   
  895.     desired = ((size+ALLOCSIZE-1)/ALLOCSIZE)*ALLOCSIZE;
  896.     if(bp->bincat == 0)
  897.     {
  898.         address = THEWELL(desired);
  899.         *remainder = desired - size;
  900.     }
  901.     else
  902.     {
  903.     struct _catlocs *cl;
  904.  
  905.         if((desired-size) > zbp.guarded)
  906.             desired -= zbp.guarded;
  907.         
  908.         address = Cmalloc(0, desired);
  909.         *remainder = desired - size;
  910.  
  911.         /* save the gross allocations for the category */
  912.         cl = new_catloc();
  913.         cl->addr = address;
  914.         cl->fptr = bp->catlocs;
  915.         bp->catlocs = cl;
  916.     }
  917.     /* maintain address range info */
  918.     if((unsigned)address < bp->minloc)
  919.         bp->minloc = (unsigned)address;
  920.     if(((unsigned)address + desired) > bp->maxloc)
  921.         bp->maxloc = (unsigned)address + desired;
  922.      if(bp->minloc < minloc)
  923.          minloc = bp->minloc;
  924.      if(bp->maxloc > maxloc)
  925.          maxloc = bp->maxloc;
  926.     return address;
  927. }
  928. static void
  929. addto_sizelist(struct _bins *bp, AddrP ap)
  930. {
  931. SKIPVARS;
  932.  
  933.     /* INSERT IN SIZE LIST */
  934.     FINDKEY(SIZEH, ap->size)
  935.  
  936.     if(node->key == ap->size)
  937.     {/* size node exists */
  938.         ap->fptr = (AddrP)node->value;
  939.         ap->bptr = (AddrP)&node->value;
  940.         if(ap->fptr) ap->fptr->bptr = ap;
  941.         node->value = (unsigned)ap;
  942.     }
  943.     else
  944.     {/* create new size node */
  945.         SETLEVEL(SIZEH)
  946.         node = new_Mnode(bp, level, SIZEH);
  947.         node->key = ap->size;
  948.         node->value = (unsigned)ap;
  949.         ap->fptr = 0;
  950.         ap->bptr = (AddrP)&node->value;
  951.         INSERT()
  952.     }
  953. }
  954. static void
  955. addto_freelist(struct _bins *bp, void *addr, unsigned size)
  956. {
  957. SKIPVARS;
  958. AddrP ap,sp;
  959. unsigned dsize[2];
  960.  
  961.     /* GET NEW ADDR STRUCT */
  962.     ap = new_addr(bp);
  963.     ap->size = size;
  964.  
  965.     dsize[1] = dsize[0] = 0; /* sizenode deletion markers */
  966.  
  967.     /* CHECK FREE LIST */
  968.     FINDKEY(FREEH, (unsigned)addr)
  969.  
  970.     /* CHECK FOR MERGE OR INSERT */
  971.     if(prev->value && prev->key+((AddrP)prev->value)->size == (unsigned)addr)
  972.     {/* merge with previous block */
  973.         ap->size += ((AddrP)prev->value)->size;
  974.  
  975.         if(prev->key + ap->size == node->key)
  976.         {/* merge with previous and next block */
  977.             sp = (AddrP) node->value;;
  978.             ap->size += sp->size;
  979.  
  980.             /* delete size struct for next block */
  981.             UNLINK(sp, 0)
  982.  
  983.             /* delete next block */
  984.             DELETENODE(FREEH);
  985.         }
  986.         /* delete size struct for prev block */
  987.         sp = (AddrP)prev->value;
  988.         UNLINK(sp, 1)
  989.  
  990.         /* set new address struct */
  991.         prev->value = (unsigned)ap;
  992.         ap->maddr = prev;
  993.     }
  994.     else if(node->value && (char*)addr + size == (void*)node->key)
  995.     {/* merge with next block */
  996.         sp = (AddrP) node->value;;
  997.         node->key = (unsigned)addr;
  998.         ap->size += sp->size;
  999.  
  1000.         /* unlink size struct for next block */
  1001.         UNLINK(sp,0)
  1002.  
  1003.         /* set new address struct */
  1004.         node->value = (unsigned)ap;
  1005.         ap->maddr = node;
  1006.     }
  1007.     else
  1008.     {/* insert in free list */
  1009.  
  1010.         SETLEVEL(FREEH)
  1011.         node = new_Mnode(bp, level, FREEH);
  1012.         node->key = (unsigned)addr;
  1013.         node->value = (unsigned)ap;
  1014.         ap->maddr = node;
  1015.         INSERT()
  1016.     }
  1017.     addto_sizelist(bp, ap);
  1018.  
  1019.     /* Remove sizenodes eliminated by merge */
  1020.     if(dsize[0])
  1021.     {
  1022.         FINDKEY(SIZEH, dsize[0])
  1023.         if(node->value == 0)
  1024.           DELETENODE(SIZEH)
  1025.     }
  1026.     if(dsize[1])
  1027.     {
  1028.         FINDKEY(SIZEH, dsize[1])
  1029.         if(node->value == 0)
  1030.           DELETENODE(SIZEH)
  1031.     }
  1032. }
  1033.  
  1034. LOCAL void* 
  1035. Cmemalign(int category, unsigned alignment, unsigned req)
  1036. {
  1037. SKIPVARS;
  1038. NodePM fnode;
  1039. unsigned remainder;
  1040. unsigned *address;
  1041. struct _bins *bp;
  1042. unsigned mask, size;
  1043.  
  1044.  
  1045.     if(!(bp = getcat(category)))
  1046.       if(!(bp = initcat(category)))
  1047.         return 0;
  1048. HEAPCHECK
  1049.     if(req == 0)
  1050.         req = ALIGNMENTM;
  1051.     else
  1052.         req += ROUNDINGM(req);
  1053.     size = req += bp->guarded;
  1054.  
  1055.     if(alignment)
  1056.     {
  1057.         alignment += ROUNDINGM(alignment);
  1058.         if(alignment > ALIGNMENTM)
  1059.         {
  1060.             mask = alignment -1;
  1061.             size = req + alignment + bp->guarded;
  1062.         }
  1063.         else
  1064.         {
  1065.             alignment = 0;
  1066.         }
  1067.     }
  1068.  
  1069.     /* check sizelist for candidate */
  1070.     FINDKEY(SIZEH, size)
  1071.     fnode = node;
  1072. trynext:
  1073.     if(node->key != 0xffffffff)
  1074.     {/* found an appropriately sized block */
  1075.     AddrP sp = (AddrP)node->value;
  1076.  
  1077.         if(!sp && node == fnode)
  1078.         {
  1079.         NodePM q;
  1080.             q = node->fptr[0];
  1081.             DELETENODE(SIZEH)
  1082.             node = q;
  1083.             goto trynext;
  1084.         }
  1085.         if(!sp)
  1086.         {/* no available space at this size */
  1087.             node = node->fptr[0];
  1088.             goto trynext;
  1089.         }
  1090.  
  1091.         /* extract some space from this block */
  1092.         remainder = node->key - size;
  1093.         address = (void*)sp->maddr->key;
  1094.         sp->maddr->key += size;
  1095.         DETACH(sp);
  1096.  
  1097.         if(node->value == 0)
  1098.         {/* no more blocks of this size, delete sizenode */
  1099.             if(node != fnode)
  1100.               FINDKEY(SIZEH, size)
  1101.             DELETENODE(SIZEH)
  1102.         }
  1103.  
  1104.         if(remainder == 0)
  1105.         {/* no remaining space,the node in freelist is exhausted, delete it */
  1106.             FINDKEY(FREEH, sp->maddr->key)
  1107.             DELETENODE(FREEH)
  1108.             free_addr(bp, sp);
  1109.         }
  1110.         else
  1111.         {/* space remains in block, move it to new size loc */
  1112.             sp->size = remainder;
  1113.             addto_sizelist(bp, sp);
  1114.         }
  1115.     }
  1116.     else
  1117.     {
  1118.         address = getspace(bp, size, &remainder);
  1119.         if(remainder)
  1120.           addto_freelist(bp, ((char*)address)+size, remainder);
  1121.     }
  1122.     if(alignment)
  1123.     {
  1124.     unsigned diff;
  1125.         if((diff = (unsigned)address & mask))
  1126.         {/* move address forward */
  1127.         char *naddress;
  1128.         unsigned lose;
  1129.             lose = alignment - diff;
  1130.             naddress = (char*)address + lose;
  1131.             addto_freelist(bp, address, lose);
  1132.             address = (unsigned*)naddress;
  1133.         }
  1134.     }
  1135.     if(bp->guarded)
  1136.     {
  1137.       *address = FRNTGUARD;
  1138.       *((unsigned*)(((char*)address)+req-ALIGNMENTM)) = BACKGUARD;
  1139.  
  1140.     }
  1141.  
  1142.     FINDKEY(USEDH, (unsigned)address)
  1143.  
  1144.     if(node->key == (unsigned)address) {
  1145.       PERROR(pName ":ERROR:allocC:%d: bookkeeping nodes are corrupted at:0x%x\n",
  1146.           category, address);
  1147.     }
  1148.     SETLEVEL(USEDH)
  1149.     node = new_Mnode(bp, level, USEDH);
  1150.     node->key = (unsigned)address;
  1151.     node->value = req;
  1152.     INSERT()    
  1153.  
  1154.     return address+bp->addrbump;
  1155. }
  1156. LOCAL void*
  1157. Ccalloc(int category, unsigned cnt, unsigned elem_size)
  1158. {
  1159. unsigned size = cnt * elem_size;
  1160. void* buf;;
  1161.  
  1162.   if((buf = Cmalloc(category, size)))
  1163.       bzero(buf, size);
  1164.   return buf;
  1165. };
  1166. LOCAL void
  1167. Cfree(int category, void* addr)
  1168. {
  1169. unsigned cursize;
  1170. unsigned *address;
  1171. struct _bins *bp;
  1172. SKIPVARS;
  1173.     if(addr)
  1174.     {
  1175.         if(!(bp = getcat(category))) {
  1176.             PERROR(pName ":ERROR:Cfree:%d: non-existant category at:0x%x\n",category,addr);
  1177.         }
  1178. HEAPCHECK
  1179.         address = (void*) ((unsigned*)addr - bp->addrbump);
  1180.         FINDKEY(USEDH, (unsigned)address)
  1181.         if(node->key != (unsigned)address) {
  1182.           PERROR(pName ":ERROR:Cfree:%d: bogus address=0x%x\n", category, addr);
  1183.         }
  1184.         cursize = node->value;
  1185.         CHECKGUARDS(Cfree)
  1186.         DELETENODE(USEDH)
  1187.  
  1188.         addto_freelist(bp, address, cursize);
  1189.     }
  1190.     else PERROR(pName ":ERROR:Cfree:%d: null pointer\n", category);
  1191. }
  1192. LOCAL void* 
  1193. Crealloc(int category, void* addr, unsigned newsize)
  1194. {
  1195. SKIPVARS;
  1196. unsigned cursize;
  1197. unsigned *address;
  1198. struct _bins *bp;
  1199. NodePM onode;
  1200.  
  1201.     if(addr == 0) 
  1202.         return Cmalloc(category, newsize);
  1203.     else
  1204.     {
  1205.         if(!(bp = getcat(category))) {
  1206.            PERROR(pName ":ERROR:reallocC:%d: non-existant category at:%x\n",category,addr);
  1207.         }
  1208. HEAPCHECK 
  1209.         if(newsize == 0)
  1210.             newsize = ALIGNMENTM;
  1211.         else
  1212.             newsize += ROUNDINGM(newsize);
  1213.         newsize += bp->guarded;
  1214.  
  1215.         address = (void*)(((char*)addr)-(bp->guarded/2));
  1216.         FINDKEY(USEDH, (unsigned)address)
  1217.         if(node->key != (unsigned)address) {
  1218.           PERROR(pName ":ERROR:reallocC:%d: bogus address=0x%x\n", category, addr);
  1219.         }
  1220.         cursize = node->value;
  1221.         node->value = newsize;
  1222.         onode = node;
  1223.  
  1224.         CHECKGUARDS(reallocC)
  1225.  
  1226.         if(newsize == cursize)
  1227.             return addr;
  1228.         if(newsize > cursize)
  1229.         {/* check if block can be extended */
  1230.         void *taddr = ((char*)address) + cursize;
  1231.         unsigned extendsize = newsize-cursize;
  1232.  
  1233.             /* check freelist for an available block at the right address */
  1234.             FINDKEY(FREEH, (unsigned)taddr)
  1235.             if(node->key == (unsigned)taddr)
  1236.             {
  1237.             AddrP sp = (AddrP)node->value;
  1238.                 if(sp->size >= extendsize)
  1239.                 {/* BLOCK CAN BE EXTENDED INTERNALLY */
  1240.                     node->key += extendsize;
  1241.                     sp->size -= extendsize;
  1242.                     DETACH(sp)
  1243.                     if(sp->size == 0)
  1244.                     {/* the extension block is used up, delete this node */
  1245.                         free_addr(bp, sp);
  1246.                         DELETENODE(FREEH)
  1247.                     }
  1248.                     else
  1249.                     {/* shift the remainder in the sizelist */
  1250.                         addto_sizelist(bp, sp);
  1251.                     }
  1252.                     /* SUCCESS */
  1253.                     if(bp->guarded)
  1254.                     {
  1255.                         *((unsigned*)(((char*)address)+newsize-ALIGNMENTM))
  1256.                             = BACKGUARD;
  1257.                     }
  1258.                     return addr;
  1259.                 }
  1260.             }
  1261.             /* HERE WE COULD CHECK OTHER SOURCES OF SPACE */
  1262.  
  1263.             /* can't extend block, malloc some new space */
  1264.             if((taddr = Cmalloc(category,newsize-bp->guarded)))
  1265.             {
  1266.                 memmove(taddr,addr,cursize-bp->guarded);
  1267.                 onode->value = cursize;
  1268.                 Cfree(category, addr);
  1269.             }
  1270.             /* SUCCESS */
  1271.             return taddr;
  1272.         }
  1273.         else
  1274.         {/* shrink block */
  1275.             if(bp->guarded)
  1276.             {
  1277.                 *((unsigned*)(((char*)address)+newsize-ALIGNMENTM))
  1278.                     = BACKGUARD;
  1279.             }
  1280.             addto_freelist(bp, ((char*)address)+newsize, cursize-newsize); 
  1281.             return addr;
  1282.         }
  1283.       }
  1284. }
  1285. LOCAL void
  1286. Cfreecat(int category)
  1287. {
  1288. struct _bins *bp;
  1289.  
  1290.     if(category == 0)
  1291.         return;
  1292.  
  1293.     if((bp = getcat(category)))
  1294.     {
  1295.     struct _catlocs *cl = bp->catlocs;
  1296.     struct _bins *hbp;
  1297.     struct _bins *prev;
  1298.  
  1299.         while(cl)
  1300.         {/* Space allocated to the category is moved to category 0 */
  1301.         void *ql = cl->fptr;
  1302.  
  1303.             Cfree(0, cl->addr);
  1304.             free_catloc(cl);
  1305.             cl = ql;
  1306.         }
  1307.         /* space for the _bins struct is placed on a free list */
  1308.         hbp = hmap[category % 1009];
  1309.         prev = 0;
  1310.         while(hbp)
  1311.         {
  1312.             if(hbp->bincat == category)
  1313.             {
  1314.                 if(prev == 0)
  1315.                     hmap[category % 1009] = hbp->fptr;
  1316.                 else
  1317.                     prev->fptr = hbp->fptr;
  1318.                 free_bins(hbp);
  1319.                 return;
  1320.             }
  1321.             prev = hbp;
  1322.             hbp = hbp->fptr;
  1323.         }
  1324.     }
  1325. }
  1326. LOCAL int
  1327. Cmemrange(int category, unsigned *min, unsigned *max)
  1328. {
  1329. struct _bins *bp;
  1330.  
  1331.     if((bp = getcat(category)))
  1332.     {
  1333.         *min = bp->minloc;
  1334.         *max = bp->maxloc;
  1335.         return 1;
  1336.     }
  1337.     return 0;
  1338. }
  1339. LOCAL int
  1340. Cusedrange(int category, unsigned *min, unsigned *max)
  1341. {
  1342. struct _bins *bp;
  1343. NodePM node;
  1344. int level;
  1345.  
  1346.     if((bp = getcat(category)))
  1347.     {
  1348.         node = bp->USEDHheader;
  1349.         *min = node->fptr[0]->key;
  1350.         for(level = bp->USEDHlevel; level >= 0; level--)
  1351.           while(node->fptr[level]->key < 0xffffffff)
  1352.             node = node->fptr[level];
  1353.         *max = node->key;
  1354.         return 1;
  1355.     }
  1356.     return 0;
  1357. }
  1358. LOCAL void
  1359. Ctotrange(unsigned *min, unsigned *max)
  1360. {
  1361.     *min = minloc;
  1362.     *max = maxloc;
  1363. }
  1364. LOCAL void
  1365. Cguard(int category)
  1366. {
  1367. struct _bins *bp;
  1368.  
  1369.     if(!(bp = getcat(category)))
  1370.       if(!(bp = initcat(category)))
  1371.           return;
  1372.  
  1373.     if(!bp->guarded)
  1374.     {
  1375.         bp->guarded = 2*ALIGNMENTM;
  1376.         bp->addrbump = 1;
  1377.     }
  1378. }
  1379. LOCAL void*
  1380. Cheapcheck(int category, void *start)
  1381. {
  1382. struct _bins *bp;
  1383. NodePM node,prev;
  1384. unsigned *p1,*p2;
  1385.  
  1386.     if((bp = getcat(category)))
  1387.     {
  1388.         if(bp->guarded)
  1389.         {
  1390.             prev = 0;
  1391.             node = bp->USEDHheader;
  1392.             while(        (node = node->fptr[0]) != (NodePM)0xffffffff
  1393.                     &&    node->key != 0xffffffffUL)
  1394.             {
  1395.                 if((void*)node->key > start)
  1396.                 {
  1397.                     p1 = (unsigned*)node->key;
  1398.                     if(*p1 != FRNTGUARD)
  1399.                     {
  1400.                         if(prev)
  1401.                             return (char*)prev->key+ALIGNMENTM;
  1402.                         else
  1403.                             return (void*)1;
  1404.                     }
  1405.                     p2 = (unsigned*)(((char*)p1)+node->value-ALIGNMENTM);
  1406.                     if(*p2 != BACKGUARD)
  1407.                         return (char*)node->key+ALIGNMENTM;
  1408.                 }
  1409.                 prev = node;
  1410.             }
  1411.         }
  1412.     }
  1413.     return 0;
  1414. }
  1415. LOCAL void* 
  1416. Cmalloc(int category, unsigned size)
  1417. {
  1418.     return Cmemalign(category, 0, size);
  1419. }
  1420.  
  1421. LOCAL void* 
  1422. Cvalloc(int category, unsigned bytes)
  1423. {
  1424.   return Cmemalign (category, PAGESIZE, bytes);
  1425. }
  1426. LOCAL unsigned
  1427. Cmallocsize(int category, void* addr)
  1428. {
  1429. struct _bins *bp;
  1430. SKIPVARS;
  1431.  
  1432.     if(addr && (bp = getcat(category)))
  1433.     {
  1434.     unsigned address = (unsigned)((unsigned*)addr - bp->addrbump);
  1435.         FINDKEY(USEDH, address)
  1436.         if(node->key == address)
  1437.             return node->value - bp->guarded;
  1438.     }
  1439.     return 0;
  1440. }
  1441.  
  1442. LOCAL int
  1443. Cnewcat()
  1444. {
  1445. static unsigned int cat = BASE_CATEGORY;
  1446.     return ++cat;
  1447. }
  1448.  
  1449.  
  1450. /* ====================== END MULTI-HEAP MALLOC ============================ */
  1451.  
  1452. /* ====================== SYMBOL TABLE HANDLERS ============================ */
  1453.  
  1454. typedef struct _key
  1455. {
  1456.     unsigned long k[2];
  1457.     unsigned long hv;
  1458. } KEY, *KEYP;
  1459.  
  1460. typedef struct _nodeS
  1461. {/* 40 bytes -- adjust size to suit application */
  1462.     unsigned long value[4];    /* 16 bytes */
  1463.     unsigned long key[2];    /* 8 bytes */
  1464.     struct _nodeS *fptr[4];    /* 16 bytes */
  1465. } NodeS, *NodePS;
  1466.  
  1467. typedef struct _pbuf
  1468. {/* symbol table object */
  1469.     int    nbins;            /* number of bins in dictionary */
  1470.     int lastbin;        /* for seq access */
  1471.     NodePS lastptr;        /* ditto */
  1472.     int category;        /* heap number */
  1473.     char *chunkbase;    /* node allocation base */
  1474.     int chunksize;        /* number of bytes available in current chunk */
  1475.     NodePS freelist;    /* list of freed nodes for allocation */
  1476.     int level;            /* sorted level */
  1477.     int bits;            /* sorted bits */
  1478.     int bitcnt;            /* sorted bitcnt */
  1479.     NodePS header;        /* sorted header */
  1480.     NodePS bins[0];        /* bins if hashed dictionary */
  1481. } *PbufP;
  1482.  
  1483. #define SYM_MAXLEVEL 12
  1484. #define TBL ((PbufP)tbl)
  1485. #define KEYEQ(a,b) ((a)[0] == (b)[0] && (a)[1] == (b)[1])
  1486. #define KEYLT(a,b) (((a)[1] < (b)[1]) || ((a)[1] == (b)[1] && (a)[0] < (b)[0]))
  1487. #define MIN(a,b) (((a) < (b)) ? (a) : (b))
  1488.  
  1489. static struct _nodeS _nnil = {{0,0,0,0},{0xffffffff,0xffffffff},{0,0,0,0}};
  1490. static struct _nodeS *_NNIL = &_nnil;
  1491.  
  1492. static int
  1493. getSlevel (PbufP tbl)
  1494. {
  1495. int level = -1;
  1496. int bits = 0;
  1497.  
  1498.     while (bits == 0)
  1499.     {
  1500.         if (tbl->bitcnt == 0)
  1501.         {
  1502.             tbl->bits = lrandom();
  1503.             tbl->bitcnt = 15;
  1504.         }
  1505.  
  1506.         bits = tbl->bits & 3;
  1507.         tbl->bits >>= 2;
  1508.         tbl->bitcnt--;
  1509.  
  1510.         if(++level > tbl->level)
  1511.             break;
  1512.     }
  1513.     return (level > SYM_MAXLEVEL) ? SYM_MAXLEVEL : level;
  1514.  
  1515. }
  1516.  
  1517. static void
  1518. hash(void *key, KEY *cat)
  1519. {
  1520.     cat->k[0] = ((unsigned long*)key)[0];
  1521.     cat->k[1] = ((unsigned long*)key)[1];
  1522.     cat->hv = ((cat->k[0] ^ cat->k[1]) * 1103515245UL) + 12345;
  1523. }
  1524. static void
  1525. sym_hash(unsigned long *key, char *symb)
  1526. {
  1527. int len = strlen(symb);
  1528. int i;
  1529.     for(i = 0; i < len; ++i)
  1530.       ((unsigned char *)key)[i & 7] ^= symb[i];
  1531.     key[0] = ((key[0] ^ key[1]) * 1103515245UL) + 12345;
  1532.     key[1] = len;
  1533. }
  1534. static void *
  1535. new_Snode(PbufP tbl, int levels)
  1536. {
  1537. NodePS p;
  1538. int size;
  1539.     if(levels <= 3)
  1540.     {
  1541.         if(tbl->freelist)
  1542.         {
  1543.             p = tbl->freelist;
  1544.             tbl->freelist = p->fptr[0];
  1545.             p->fptr[0] = 0;
  1546.             return p;
  1547.         }
  1548.     }
  1549.     size = sizeof(struct _nodeS) + ((levels-3) * sizeof(void*));
  1550.     if(tbl->chunksize < size)
  1551.     {
  1552.         tbl->chunkbase = Ccalloc(tbl->category, 1, 4080);
  1553.         tbl->chunksize = 4080;
  1554.     } 
  1555.     tbl->chunksize -= size;
  1556.     p = (NodePS)tbl->chunkbase;
  1557.     tbl->chunkbase += size;
  1558.     return p;
  1559. }
  1560. static void
  1561. free_Snode(PbufP tbl, NodePS node)
  1562. {
  1563.     bzero(node, sizeof(struct _nodeS));
  1564.     node->fptr[0] = tbl->freelist;
  1565.     tbl->freelist = node;
  1566. }
  1567.  
  1568. static void*
  1569. NewSymTable(int category, int nbins)
  1570. {
  1571. PbufP tbl;
  1572.  
  1573.     tbl = Ccalloc(category, 1, nbins*sizeof(NodePS) + sizeof(struct _pbuf));
  1574.     if(nbins == 0)
  1575.     {/* sorted dictionary */
  1576.     int i;
  1577.         tbl->header = new_Snode(tbl, SYM_MAXLEVEL+1);
  1578.         for(i = 0; i <= SYM_MAXLEVEL; ++i)
  1579.             tbl->header->fptr[i] = _NNIL;
  1580.     }
  1581.     tbl->nbins = nbins;
  1582.     tbl->category = category;
  1583.     return tbl;
  1584. }
  1585. static int
  1586. SymFind(void *tbl, void *key, void *result)
  1587. {
  1588. NodePS node;
  1589.  
  1590.     if(tbl && key)
  1591.     {
  1592.       if(TBL->nbins)
  1593.       {/* hashed dictionary */
  1594.       KEY cat;
  1595.  
  1596.         hash(key, &cat);
  1597.         if((node = TBL->bins[cat.hv % TBL->nbins]))
  1598.         {
  1599.             do {
  1600.                 if(        node->key[0] == cat.k[0]
  1601.                     &&    node->key[1] == cat.k[1])
  1602.                 {
  1603.                     if(result)
  1604.                       *((NodePS *)result) = node;
  1605.                     TBL->lastbin = cat.hv % TBL->nbins;
  1606.                     TBL->lastptr = node;
  1607.                     return 1;
  1608.                 }
  1609.              } while((node = node->fptr[0]));
  1610.         }
  1611.         return 0;
  1612.       }
  1613.       else
  1614.       {/* sorted dictionary */
  1615.       int level;
  1616.  
  1617.         node = TBL->header;
  1618.         for(level = TBL->level; level >= 0; level--)
  1619.         {
  1620.           while( KEYLT(node->fptr[level]->key, ((unsigned long*)key)) )
  1621.             node = node->fptr[level];
  1622.         }
  1623.         node = node->fptr[0];
  1624.  
  1625.         TBL->lastptr = node;
  1626.         if(result)
  1627.             *((NodePS *)result) = node;
  1628.         return (KEYEQ(node->key, ((unsigned long*)key))) ? 1 : 0;
  1629.       }
  1630.     }
  1631.     return -1;
  1632. }
  1633. static int
  1634. SymFindRange(void *tbl, void *key, void *result)
  1635. {/* assumes 4 byte key and value (the value can be bigger) */
  1636. NodePS node;
  1637.  
  1638.     if(tbl && key)
  1639.     {
  1640.       if(TBL->nbins)
  1641.       {/* hashed dictionary */
  1642.         return 0;
  1643.       }
  1644.       else
  1645.       {/* sorted dictionary */
  1646.       NodePS prev;
  1647.       int level;
  1648.  
  1649.         node = TBL->header;
  1650.         for(level = TBL->level; level >= 0; level--)
  1651.         {
  1652.           while ( node->fptr[level]->key[0] < ((unsigned long*)key)[0] )
  1653.             node = node->fptr[level];
  1654.         }
  1655.         prev = node;
  1656.         node = node->fptr[0];
  1657.  
  1658.         if( node->key[0] == ((unsigned long*)key)[0] )
  1659.         {
  1660.             TBL->lastptr = node;
  1661.             if(result)
  1662.                 *((NodePS *)result) = node;
  1663.             return 1;
  1664.         }        
  1665.         if( ((unsigned long*)key)[0] < prev->key[0]+prev->value[0] )
  1666.         {
  1667.             TBL->lastptr = prev;
  1668.             if(result)
  1669.                 *((NodePS *)result) = prev;
  1670.             return 1;
  1671.         }
  1672.         return 0;
  1673.       }
  1674.     }
  1675.     return -1;
  1676. }
  1677. static void*
  1678. SymInsert(void *tbl, void *key, void *value, int datsiz)
  1679. {
  1680. NodePS node;
  1681.  
  1682.     if(tbl && key)
  1683.     {
  1684.       if(TBL->nbins)
  1685.       {/* hashed dictionary */
  1686.       KEY cat;
  1687.       NodePS *binp;
  1688.         hash(key, &cat);
  1689.         node = new_Snode(tbl, 0);
  1690.         TBL->lastbin = cat.hv % TBL->nbins;
  1691.         TBL->lastptr = node;
  1692.         binp = &TBL->bins[TBL->lastbin];
  1693.         if(value && datsiz)
  1694.           memcpy(node, value, MIN(datsiz,16));
  1695.         node->key[0] = cat.k[0];
  1696.         node->key[1] = cat.k[1];
  1697.         node->fptr[0] = *binp;
  1698.         *binp = node;
  1699.         return node;
  1700.       }
  1701.       else
  1702.       {/* sorted dictionary */
  1703.       int level;
  1704.       NodePS update[SYM_MAXLEVEL+1];
  1705.  
  1706.         node = TBL->header;
  1707.         for (level = TBL->level; level >= 0; level--)
  1708.         {
  1709.           while ( KEYLT(node->fptr[level]->key,((unsigned long*)key)) )
  1710.             node = node->fptr[level];
  1711.           update[level] = node;
  1712.         }
  1713.  
  1714.         level = getSlevel(tbl);
  1715.  
  1716.         while(TBL->level < level)
  1717.             update[++TBL->level] = TBL->header;
  1718.  
  1719.         node = new_Snode(tbl, level);
  1720.  
  1721.         if(value && datsiz)
  1722.           memcpy(node, value, MIN(datsiz,16));
  1723.         node->key[0] = ((unsigned long*)key)[0];
  1724.         node->key[1] = ((unsigned long*)key)[1];
  1725.  
  1726.         while(level >= 0)
  1727.         {
  1728.             node->fptr[level] = update[level]->fptr[level];
  1729.             update[level]->fptr[level] = node;
  1730.             level--;
  1731.         }
  1732.         TBL->lastptr = node;
  1733.         return node;
  1734.      }
  1735.     }
  1736.     return 0;
  1737. }
  1738. static int
  1739. StringFind(void *tbl, char *string, void *result)
  1740. {
  1741. unsigned long key[2];
  1742. struct {
  1743.     char *symname;
  1744. } *valp;
  1745.  
  1746.     key[0] = 0;
  1747.     key[1] = 0;
  1748.     sym_hash(key, string);
  1749.  
  1750.     if(SymFind(tbl, key, &valp) == 1)
  1751.     {
  1752.     unsigned long *key1;
  1753.         do {
  1754.             if(!strcmp(string, valp->symname))
  1755.             {
  1756.                 if(result)
  1757.                     *((void **)result) = valp;
  1758.                 return 1;
  1759.             }
  1760.             /* Check duplicates */
  1761.             if(!SymNext(tbl))
  1762.                 break;
  1763.             SymKey(tbl, &key1);
  1764.             SymValue(tbl, &valp);
  1765.         } while(KEYEQ(key, key1));
  1766.     }
  1767.     return 0;
  1768. }
  1769. static int
  1770. StringInsert(void *tbl, char *string, void *result)
  1771. {
  1772. unsigned long key[2];
  1773. struct {
  1774.     char *symname;
  1775. } *valp;
  1776.  
  1777.     key[0] = 0;
  1778.     key[1] = 0;
  1779.     sym_hash(key, string);
  1780.     if(SymFind(tbl, key, &valp) == 1)
  1781.     {/* hash keys match */
  1782.     unsigned long *key1;
  1783.         do {
  1784.             if(!strcmp(string, valp->symname))
  1785.             {
  1786.                 if(result)
  1787.                     *((void **)result) = valp;
  1788.                 return 1;
  1789.             }
  1790.             /* Check duplicates */
  1791.             if(!SymNext(tbl))
  1792.                 break;
  1793.             SymKey(tbl, &key1);
  1794.             SymValue(tbl, &valp);
  1795.         } while(KEYEQ(key, key1));
  1796.     }
  1797.     /* NOMATCH */
  1798.     valp = SymInsert(tbl, key, &string, 4);
  1799.     if(result)
  1800.         *((void**)result) = valp;
  1801.     return 0;
  1802. }
  1803. static void
  1804. SymDelete(void *tbl, void *key)
  1805. {
  1806. NodePS node;
  1807.  
  1808.     if(tbl && key)
  1809.     {
  1810.       if(TBL->nbins)
  1811.       {/* hashed dictionary */
  1812.       KEY cat;
  1813.       NodePS *binp;
  1814.       NodePS prev = 0;
  1815.  
  1816.         hash(key, &cat);
  1817.         binp = &TBL->bins[cat.hv % TBL->nbins];
  1818.         if((node = *binp))
  1819.         {
  1820.             do {
  1821.                 if(        node->key[0] == cat.k[0]
  1822.                     &&    node->key[0] == cat.k[1])
  1823.                 {
  1824.                     if(prev)
  1825.                         prev->fptr[0] = node->fptr[0];
  1826.                     else
  1827.                         *binp = node->fptr[0];
  1828.  
  1829.                     free_Snode(tbl, node);
  1830.                     if(TBL->lastptr == node)
  1831.                     {
  1832.                         TBL->lastptr = 0;
  1833.                         TBL->lastbin = TBL->nbins;
  1834.                     }
  1835.                     return;
  1836.                 }
  1837.                 prev = node;
  1838.              } while((node = node->fptr[0]));
  1839.         }
  1840.       }
  1841.       else
  1842.       {/* sorted dictionary */
  1843.       int level;
  1844.       NodePS update[SYM_MAXLEVEL+1];
  1845.  
  1846.         node = TBL->header;
  1847.         for(level = TBL->level; level >= 0; level--)
  1848.         {
  1849.           while ( KEYLT(node->fptr[level]->key, ((unsigned long*)key)) )
  1850.             node = node->fptr[level];
  1851.           update[level] = node;
  1852.         }
  1853.         node = node->fptr[0];
  1854.  
  1855.         if( KEYEQ(node->key, ((unsigned long*)key)) )
  1856.         {
  1857.             for(level = 0; level <= TBL->level; level++)
  1858.             {
  1859.                 if (update[level]->fptr[level] == node)
  1860.                      update[level]->fptr[level] = node->fptr[level];
  1861.                 else break;
  1862.             }
  1863.  
  1864.             while((TBL->level > 0) && (TBL->header->fptr[TBL->level] == _NNIL))
  1865.                 TBL->level--;
  1866.  
  1867.             if(TBL->lastptr == node)
  1868.                 TBL->lastptr = 0;
  1869.             free_Snode(tbl, node);
  1870.         }
  1871.       }
  1872.     }
  1873. }
  1874. static int
  1875. SymHead(void *tbl)
  1876. {/* Set up for sequential access */
  1877. int nbins;
  1878.  
  1879.     if(tbl)
  1880.     {
  1881.       if((nbins = TBL->nbins))
  1882.       {/* hashed dictionary */
  1883.       NodePS node;
  1884.       int i;
  1885.         TBL->lastptr = 0;
  1886.         for(i = 0; i < nbins; ++i)
  1887.         {
  1888.             if( (node = TBL->bins[i]) != 0)
  1889.             {
  1890.                 TBL->lastbin = i;
  1891.                 return 1;
  1892.             }
  1893.         }
  1894.         TBL->lastbin = nbins;
  1895.         return 0; /* empty */
  1896.       }
  1897.       else
  1898.       {/* sorted dictionary */
  1899.         TBL->lastptr = TBL->header;
  1900.         return (TBL->lastptr->fptr[0] == _NNIL) ? 0 : 1;
  1901.       }
  1902.     }
  1903.     return 0;
  1904. }
  1905. static int
  1906. SymNext(void *tbl)
  1907. {/* Move to next sequential entry */
  1908. int nbins;
  1909.  
  1910.     if(tbl)
  1911.     {
  1912.       if((nbins = TBL->nbins))
  1913.       {/* hashed dictionary */
  1914.         if(TBL->lastptr && ((TBL->lastptr = TBL->lastptr->fptr[0])))
  1915.             return 1;
  1916.         else
  1917.         {
  1918.         int i;
  1919.             for(i = TBL->lastbin; i < nbins; ++i)
  1920.             {
  1921.                 if((TBL->lastptr = TBL->bins[i]) != 0)
  1922.                 {
  1923.                     TBL->lastbin = i+1;
  1924.                     return 1;
  1925.                 }
  1926.             }
  1927.             return 0;
  1928.         }
  1929.       }
  1930.       else
  1931.       {/* sorted dictionary */
  1932.         if(TBL->lastptr)
  1933.         {
  1934.             if(TBL->lastptr != _NNIL)
  1935.                 TBL->lastptr = TBL->lastptr->fptr[0];
  1936.             return (TBL->lastptr == _NNIL) ? 0 : 1;
  1937.         }
  1938.       }
  1939.     }
  1940.     return 0;
  1941. }
  1942. static void
  1943. SymGetMark(void *tbl, void *markptr)
  1944. {
  1945.     if(tbl && markptr)
  1946.     {
  1947.         ((long*)markptr)[0] = TBL->lastbin;
  1948.         ((long*)markptr)[1] = (long)TBL->lastptr;
  1949.     }
  1950. }
  1951. static int
  1952. SymMarkNext(void *tbl, void *mark)
  1953. {/* Mark current position, and move to next sequential entry */
  1954.     SymGetMark(tbl, mark);
  1955.     return SymNext(tbl);
  1956. }
  1957. static void
  1958. SymSetMark(void *tbl, void *markptr)
  1959. {
  1960.     if(tbl && markptr)
  1961.     {
  1962.         TBL->lastbin = ((long*)markptr)[0];
  1963.         TBL->lastptr = (NodePS)((long*)markptr)[1];
  1964.     }
  1965. }
  1966. static void
  1967. SymKey(void *tbl, void *keyptr)
  1968. {/* Retrieve key info pointer for current spot */
  1969.  
  1970.     if(tbl && keyptr && TBL->lastptr)
  1971.         *((unsigned long**)keyptr) = &TBL->lastptr->key[0];
  1972. }
  1973. static void
  1974. SymValue(void *tbl, void *datptr)
  1975. {/* Retrieve value pointer for current spot */
  1976.  
  1977.     if(tbl && datptr && TBL->lastptr)
  1978.         *((unsigned long**)datptr) = &TBL->lastptr->value[0];
  1979. }
  1980.  
  1981. /* ==================== END SYMBOL TABLE HANDLERS ========================== */
  1982.  
  1983. /* ========================== OPTIMIZATION ================================= */
  1984. static int
  1985. forward(unsigned char *p)
  1986. {
  1987. unsigned char *next;
  1988.  
  1989.     do {
  1990.         next = (void*)((Pop)p)->next;
  1991.         while(        *next == 0
  1992.                 ||    *next == lineop
  1993.                 ||    *next == labelop)
  1994.             next = (void*)((Pop)next)->next;
  1995.  
  1996.         if(*next == endop)
  1997.         {
  1998.             if(*p == *(next+8))
  1999.             {
  2000.                 *p = 0;
  2001.                 *next = 0;
  2002.                 return 1;
  2003.             }
  2004.             return 0;
  2005.         }
  2006.     } while(forward(next));
  2007.  
  2008.     return 0;
  2009. }
  2010. static void
  2011. eliminate_extraneous_infops(Piv iv, int level)
  2012. {
  2013. Pafile pf;
  2014. unsigned char *p;
  2015. int i;
  2016.     for(i = 0; i < iv->numfiles; ++i)
  2017.     {
  2018.         iv->filenum = i;
  2019.         pf = iv->files[i];
  2020.         if(!(p = pf->prog_p))
  2021.             continue;
  2022.         if(pf->header_p->hdr.opt_level >= level)
  2023.             continue;
  2024.         pf->header_p->hdr.opt_level = level;
  2025.         while(*p != endfileop)
  2026.         {
  2027.             switch(*p)
  2028.             {
  2029.                 case    unopop:
  2030.                 case    arrayelemop:
  2031.                 case    ptrelemop:
  2032.                 case    strelemop:
  2033.                 case    ptrdimsop:
  2034.                 case    arraydimsop:
  2035.                     forward(p);
  2036.                     break;
  2037.             }
  2038.             p = POP->next;
  2039.         }
  2040.     }
  2041. }
  2042.  
  2043. static void
  2044. clean_temps(Piv iv)
  2045. {
  2046. long *key;
  2047. long *val;
  2048. long hitemp = iv->first_temp & 0xffff0000;
  2049.  
  2050.     if(iv->temps_written == 0)
  2051.         return;
  2052.     if(SymHead(iv->tmptbl))
  2053.     {
  2054.         while(SymNext(iv->tmptbl))
  2055.         {
  2056.             SymKey(iv->tmptbl, &key);
  2057.  
  2058.             if((key[0] & 0xffff0000) == hitemp)
  2059.             {
  2060.             char *ptr;
  2061.             long saveit;
  2062.  
  2063.                 SymValue(iv->tmptbl, &val);
  2064.                 saveit = val[1];
  2065.                 ptr = (void*)val[0];
  2066.  
  2067.                 val[0] = 0;    /* allow reuse of this slot */
  2068.                 val[1] = 0;
  2069.  
  2070.                 while(ptr)
  2071.                 {
  2072.                 void *nptr = (void*)((PopT)ptr)->tmpnum;
  2073.                     ((PopT)ptr)->tmpnum = key[0];
  2074.                     if(!saveit)
  2075.                     {
  2076.                         *(ptr-8) = 0;                        
  2077.                         ++iv->killop;
  2078.                     }
  2079.                     ptr = nptr;
  2080.                 }
  2081.             }
  2082.         }
  2083.         if(!hitemp)
  2084.             iv->temps_written = 0;
  2085.     }
  2086. }
  2087.  
  2088. static void
  2089. read_temp(Piv iv, PopT ptr, unsigned long last)
  2090. {
  2091. unsigned long key[2];
  2092. long *result;
  2093.  
  2094.     if(last == ptr->tmpnum)
  2095.         return;
  2096.  
  2097.     key[0] = ptr->tmpnum;
  2098.     key[1] = 0;
  2099.  
  2100.     if(SymFind(iv->tmptbl, key, &result) == 1)
  2101.     {
  2102.         result[1] = 1;
  2103.     }
  2104.     else PERROR(pName ":SYSERROR: read temp %d not found\n", key[0]);
  2105. }
  2106. static long
  2107. write_temp(Piv iv, PopT ptr)
  2108. {
  2109. long key[2];
  2110. long val[2];
  2111. long *result;
  2112. long hitemp = ptr->tmpnum & 0xffff0000;
  2113.  
  2114.     if(ptr->atype & A_MEMADDR)
  2115.     {/* actually reading from this destination slot */
  2116.         read_temp(iv, ptr, 0);
  2117.         return 0;
  2118.     }
  2119.  
  2120.     if(hitemp > (iv->first_temp & 0xffff0000))
  2121.     {/* Inner block, CompoundExp or NestedFunc */
  2122.         iv->first_temp = hitemp + 1;
  2123.     }
  2124.     else if(hitemp < (iv->first_temp & 0xffff0000))
  2125.     {/* Exit inner block */
  2126.         while(hitemp < (iv->first_temp & 0xffff0000))
  2127.         {
  2128.             clean_temps(iv);
  2129.             iv->first_temp -= 0x00010000;
  2130.         }
  2131.     }
  2132.     if(ptr->tmpnum == iv->first_temp)
  2133.     {
  2134.         clean_temps(iv);
  2135.     }
  2136.     ++iv->temps_written;
  2137.     key[0] = ptr->tmpnum;
  2138.     key[1] = 0;
  2139.  
  2140.     if(SymFind(iv->tmptbl, key, &result) == 1)
  2141.     {
  2142.     PopT optr = (PopT)result[0];
  2143.         result[0] = (long)ptr;
  2144.         ptr->tmpnum = (long)optr;
  2145.     }
  2146.     else
  2147.     {
  2148.         val[0] = (long)ptr;
  2149.         val[1] = 0;
  2150.         SymInsert(iv->tmptbl, key, val, 8);
  2151.         ptr->tmpnum = 0;
  2152.     }
  2153.     return key[0];
  2154. }
  2155. static void
  2156. eliminate_unused_temps(Piv iv, int level)
  2157. {
  2158. Pafile pf;
  2159. unsigned char *p;
  2160. int i;
  2161. long last_write;
  2162.  
  2163.     iv->tmptbl = NewSymTable(iv->category, 111);
  2164.     for(i = 0; i < iv->numfiles; ++i)
  2165.     {
  2166.         iv->filenum = i;
  2167.         pf = iv->files[i];
  2168.         if(pf->header_p->hdr.opt_level >= level)
  2169.             continue;
  2170.         pf->header_p->hdr.opt_level = level;
  2171. rekill:
  2172.         if(!(p = pf->prog_p))
  2173.             continue;
  2174.         iv->first_temp = 1;
  2175.         iv->temps_written = 0;
  2176.         iv->killop = 0;
  2177.         while(*p != endfileop)
  2178.         {
  2179.             if(*p < labelop)
  2180.             {
  2181.                 if(*p == truthop)
  2182.                 {/* truthops of single chars are unnecessary */
  2183.                   if((p[2] & 0xe0) == OPTEMP)
  2184.                   {
  2185.                     if(((PopT)(p+20))->dsize == 1)
  2186.                     {
  2187.                         if(((PopT)(p+8))->tmpnum == ((PopT)(p+20))->tmpnum)
  2188.                         {
  2189.                             *p = 0;
  2190.                         }
  2191.                         else
  2192.                         {/* may be needed for code generation */
  2193.                             *p = aliastmpop;
  2194.                         }
  2195.                     }
  2196.                   }
  2197.                 }
  2198.                 if(*p)
  2199.                 {
  2200.                     if(*p == jmptrueop || *p == jmpfalseop)
  2201.                         read_temp(iv,(PopT)(p+4), 0);
  2202.                     else
  2203.                     {
  2204.                         last_write = 0;
  2205.                         if((p[1] & 0xe0) == OPTEMP)
  2206.                             last_write = write_temp(iv, (PopT)(p+8));
  2207.                         if((p[2] & 0xe0) == OPTEMP)
  2208.                             read_temp(iv, (PopT)(p+8+(p[1]&0x1f)), last_write);
  2209.                         if((p[3] & 0xe0) == OPTEMP)
  2210.                             read_temp(iv, (PopT)(p+8+(p[1]&0x1f)+(p[2]&0x1f)), last_write);
  2211.                     }
  2212.                 }
  2213.             }
  2214.             p = POP->next;
  2215.         }
  2216.         do {
  2217.             clean_temps(iv);
  2218.             iv->first_temp -= 0x00010000;
  2219.         } while(iv->first_temp > 0);
  2220.         if(iv->killop)
  2221.             goto rekill;
  2222.     }
  2223. }
  2224. static void
  2225. retarget_jmps(Piv iv, int level)
  2226. {
  2227. Pafile pf;
  2228. unsigned char *p;
  2229. int i;
  2230.     for(i = 0; i < iv->numfiles; ++i)
  2231.     {
  2232.         iv->filenum = i;
  2233.         pf = iv->files[i];
  2234.         if(!(p = pf->prog_p))
  2235.             continue;
  2236.         if(pf->header_p->hdr.opt_level >= level)
  2237.             continue;
  2238. #if 0
  2239.         pf->header_p->hdr.opt_level = level;
  2240.         while(*p != endfileop)
  2241.         {
  2242.             p = POP->next;
  2243.         }
  2244. #endif
  2245.     }
  2246. }
  2247.  
  2248. static void
  2249. optimize(Piv iv)
  2250. {
  2251.     eliminate_extraneous_infops(iv, 50);
  2252.     eliminate_unused_temps(iv, 51);
  2253.     retarget_jmps(iv, 52);
  2254. }
  2255. /* ========================== END OPTIMIZATION ============================= */
  2256. /* ====================== BASIC INPUT FILE PROCESSING ====================== */
  2257. static long
  2258. label_insert(Piv iv, long label, int filenum)
  2259. {
  2260. struct {
  2261.     long k1;
  2262.     long k2;
  2263. } key;
  2264.  
  2265. struct {
  2266.     long newlabel;
  2267. } val;
  2268.  
  2269.     key.k1 = label;
  2270.     key.k2 = filenum;
  2271.     val.newlabel = ++iv->lastlabel;
  2272.  
  2273.     SymInsert(iv->labeltbl, &key, &val, 4);
  2274. #if REALLY_NEED_OFFSETS
  2275.     key.k1 = val.newlabel;
  2276.     val.newlabel = -1;
  2277.     SymInsert(iv->newlabeltbl, &key, &val, 4);
  2278. #endif
  2279.     return iv->lastlabel;
  2280. }
  2281. static long
  2282. label_find(Piv iv, long label, int filenum)
  2283. {
  2284. struct {
  2285.     long k1;
  2286.     long k2;
  2287. } key;
  2288.  
  2289. long *result;
  2290.  
  2291.     key.k1 = label;
  2292.     key.k2 = filenum;
  2293.  
  2294.     if(SymFind(iv->labeltbl, &key, &result) == 1)
  2295.         return *result;
  2296.     else
  2297.         return 0;
  2298. }
  2299. #if REALLY_NEED_OFFSETS
  2300. static long
  2301. newlabel_find(Piv iv, long label, int filenum)
  2302. {
  2303. struct {
  2304.     long k1;
  2305.     long k2;
  2306. } key;
  2307.  
  2308. long *result;
  2309.  
  2310.     key.k1 = label;
  2311.     key.k2 = filenum;
  2312.  
  2313.     if(SymFind(iv->newlabeltbl, &key, &result) == 1)
  2314.         return *result;
  2315.     else
  2316.         return 0;
  2317. }
  2318. #endif /* REALLY_NEED_OFFSETS */
  2319.  
  2320. static void
  2321. extern_insert(Piv iv, unsigned char *p, int filenum)
  2322. {
  2323. struct {
  2324.     short k1;
  2325.     short k2;
  2326.     long k3;
  2327. } key;
  2328. struct {
  2329.     unsigned char *p;
  2330. } val;
  2331.  
  2332.     key.k1 = GS(POPI->s.symnum);
  2333.     key.k2 = filenum;
  2334.     key.k3 = 0;
  2335.  
  2336.     val.p = p;
  2337.     SymInsert(iv->extrntbl, &key, &val, 4);
  2338. }
  2339. static void
  2340. reloc_insert(Piv iv, int fileno, unsigned char *p)
  2341. {
  2342. struct {
  2343.     unsigned long spot;
  2344.     short fileno;
  2345.     char opcode;
  2346.     char rsize;
  2347. } key;
  2348. struct {
  2349.     unsigned char *p;
  2350.     unsigned long base;
  2351.     long offset;
  2352.     short rsym;
  2353. } val;
  2354.  
  2355.     key.spot = GL(POPI->reloc.spot);        /* reloc target offset */
  2356.     key.fileno = (short)fileno;                /* fileno */
  2357.     key.opcode = *p;                        /* opcode */
  2358.     key.rsize = GL(POPI->reloc.rsize);        /* reloc size */
  2359.  
  2360.     val.p = p;                                /* pointer to input buffer */
  2361.     val.base = GL(POPI->reloc.base);        /* base of data object pointed to */
  2362.     val.offset = GL(POPI->reloc.offset);    /* offset to be added to base */
  2363.     val.rsym = GL(POPI->reloc.rsym);        /* symbol number if external */
  2364.  
  2365.     SymInsert(iv->reloctbl, &key, &val, 14);
  2366. }
  2367. static void
  2368. data_insert(void *tbl, unsigned long offset, unsigned long size, void *p)
  2369. {
  2370. struct {
  2371.     unsigned long k1;
  2372.     long k2;
  2373. } key;
  2374. struct {
  2375.     unsigned long size;
  2376.     void *p;
  2377. } val;
  2378.  
  2379.     key.k1 = offset;
  2380.     key.k2 = 0;
  2381.  
  2382.     val.size = size;
  2383.     val.p = p;
  2384.  
  2385.     SymInsert(tbl, &key, &val, sizeof(val));
  2386. }
  2387.  
  2388. static void
  2389. global_insert(Piv iv, Pafile pf, unsigned char *p)
  2390. {
  2391. unsigned long key[2];
  2392. struct _gloval val;
  2393. PopI pp;
  2394. unsigned char opcode = *p;
  2395.  
  2396.     if(opcode == extvarop)
  2397.         pp = POPI;
  2398.     else
  2399.         pp = (PopI)(POP->next+8);
  2400.  
  2401.     key[0] = 0;
  2402.     key[1] = 0;
  2403.  
  2404.     val.symnum = GS(pp->s.symnum);
  2405.     val.symname = pf->symaddr[val.symnum];
  2406.     val.p = p;
  2407.     val.pf = pf;
  2408.  
  2409.     sym_hash(key, val.symname);
  2410.     SymInsert(iv->gbltbl, key, &val, sizeof(val));
  2411. }
  2412.  
  2413. static int
  2414. setup_nodelinks(Piv iv, char *infile_name, void *inbuf, int insize)
  2415. {
  2416. unsigned char *p = inbuf;
  2417. unsigned char *endbuf = inbuf+insize;
  2418. Pafile pf=0;
  2419. long lastline = 0;
  2420. unsigned char *funcp;
  2421. unsigned char *nfuncp;
  2422.  
  2423.     while(p < endbuf && *p != endallop)
  2424.     {
  2425.     unsigned char *q = p;
  2426.         if(iv->debug)
  2427.         {
  2428.             PRINTF("OP(%d '%s' p=%p line=%ld)\n", *p, oxgenops[*p], p, lastline);
  2429.         }
  2430.         switch(*p)
  2431.         {
  2432.             case headerop:
  2433.                 if(iv->numfiles >= 1024) {
  2434.                     PERROR(pName ": Sorry, too many files\n");
  2435.                     return 1;
  2436.                 }
  2437.                 pf = iv->files[iv->numfiles] = 
  2438.                     Ccalloc(iv->category, 1, sizeof(struct _afile));
  2439.                 pf->filenum = iv->numfiles++;
  2440.                 pf->file_p = p;
  2441.                 pf->header_p = POPI;
  2442.                 if(iv->strip)
  2443.                 {/* Gonna strip declarations and line numbers */
  2444.                     pf->header_p->hdr.target_debugger = 0;
  2445.                 }
  2446.                 break;
  2447.  
  2448.             case dataop:
  2449.                 pf->size_p = POPI;
  2450.                 pf->thunk_offset = GL(POPI->dat.thunk_offset);
  2451.                 pf->bss_offset = GL(POPI->dat.bss_offset);
  2452.                 break;
  2453.             case gfuncdefop:
  2454.             case sfuncdefop:
  2455.                 if(pf->prog_p == 0)
  2456.                     pf->prog_p = p;
  2457.                 funcp = p;
  2458.                 break;
  2459.             case funcexitop:
  2460.                 PS(((PopI)(funcp+8))->funcdef.tempmax) = GL(POPI->funcexit.tempmax);
  2461.                 break;
  2462.             case nestedfuncdefop:
  2463.                 nfuncp = p;
  2464.                 break;
  2465.             case nestedfuncexitop:
  2466.                 PS(((PopI)(nfuncp+8))->funcdef.tempmax) = GL(POPI->funcexit.tempmax);
  2467.                 break;
  2468.             case segdefop:
  2469.                 if(pf->seg_p == 0)
  2470.                     pf->seg_p = p;
  2471.                 pf->numsegs += 1;
  2472.                 iv->numsegs += 1;
  2473.                 break;
  2474.             case lineop:
  2475.                 lastline = GL( POPI->line.line );
  2476.                 if(iv->strip)
  2477.                     *p = 0;        /* strip line numbers */
  2478.                 break;
  2479.             case declop:
  2480.                 if(iv->strip)
  2481.                 {/* strip declarations */
  2482.                     do {
  2483.                         *p = 0;
  2484.                         q += (long)GL(POP->next);
  2485.                         POP->next = q;
  2486.                         p = q;
  2487.                     } while(*p != endop);                    
  2488.                     *p = 0;
  2489.                 }
  2490.                 else
  2491.                 {
  2492.                     if(pf->decl_p == 0)
  2493.                         pf->decl_p = p;
  2494.                     pf->numdecls += 1;
  2495.                     iv->numdecls += 1;
  2496.                 }
  2497.                 break;
  2498.             case switchidop:
  2499.                 if(pf->switch_p == 0)
  2500.                     pf->switch_p = p;
  2501.             /* FALL THROUGH */
  2502.             case labelop:
  2503.                 PL( POP->data ) = 
  2504.                         label_insert(iv, GL( POP->data ), pf->filenum);
  2505.                 break;            
  2506.             case symbop:
  2507.                 pf->numsyms = GL(POP->data);
  2508.                 iv->numsyms += pf->numsyms;
  2509.                 break;
  2510.             case symblockop:
  2511.                 pf->symtext_p = p + 12;
  2512.                 goto blka;
  2513.             case stringblockop:
  2514.             case datablockop:
  2515.             case mallocblockop:
  2516.             case thunkblockop:
  2517.             {
  2518.             long size;
  2519.                 if(pf->data_p == 0)
  2520.                     pf->data_p = p;
  2521. blka:
  2522.                 size = GL(POP->data);
  2523.                 q += size+((4-(size&3))&3);
  2524.                 break;
  2525.             }
  2526.             case glofuncop:
  2527.             case extfuncop:
  2528.             case glodatop:
  2529.             case globssop:
  2530.             case extvarop:
  2531.             case bssblockop:
  2532.                 if(pf->data_p == 0)
  2533.                     pf->data_p = p;
  2534.                 break;
  2535.             case maxtempop:
  2536.                 pf->maxtemp = GL(POP->data);
  2537.                 pf->maxtempclass = GL(POP->data1);
  2538.                 pf->maxtemp_p = p;
  2539.                 break;
  2540.         }
  2541.         q += (long)GL(POP->next);
  2542.         POP->next = q;
  2543.         p = q;
  2544.     }
  2545.     if(*p != endallop)
  2546.     {
  2547.         PERROR(pName ":ERROR: Malformed input file: %s\n", infile_name);
  2548.         return 1;
  2549.     }
  2550.     return 0;
  2551. }
  2552. static void
  2553. setup_syms_decls(Piv iv)
  2554. {
  2555. int i;
  2556.  
  2557.     for(i = 0; i < iv->numfiles; ++i)
  2558.     {
  2559.     int symnum = 0;
  2560.     Pafile pf = iv->files[i];
  2561.     unsigned char *p = pf->file_p;
  2562.  
  2563.         pf->symaddr = Ccalloc(iv->category, sizeof(void*), pf->numsyms);
  2564.         pf->decladdr = Ccalloc(iv->category, sizeof(void*), pf->numdecls);
  2565.  
  2566.         while(*p != endfileop)
  2567.         {
  2568.             switch(*p)
  2569.             {
  2570.                 case    symoffsetop:
  2571.                   pf->symaddr[symnum] = pf->symtext_p + GL(POP->data);
  2572.                   ++symnum;
  2573.                   break;
  2574.  
  2575.                 case    declop:
  2576.                   pf->decladdr[GS(POPI->dcl.declnum)] = p;
  2577.                   break;
  2578.  
  2579.                 case    relocop:
  2580.                 case    extlocop:
  2581.                   ++pf->numrelocs;
  2582.                   reloc_insert(iv, i, p);
  2583.                   break;
  2584.  
  2585.                 case    glodatop:
  2586.                 case    globssop:
  2587.                 case    glofuncop:
  2588.                 case    extfuncop:
  2589.                   global_insert(iv, pf, p);
  2590.                   break;
  2591.  
  2592.                 case    extvarop:
  2593.                   extern_insert(iv, p, i);
  2594.                   global_insert(iv, pf, p);
  2595.                   break;
  2596.  
  2597.                 case    stringblockop:
  2598.                 case    datablockop:
  2599.                 case    mallocblockop:
  2600.                 case    thunkblockop:
  2601.                 case    bssblockop:
  2602.                   if(!pf->datatbl)
  2603.                     pf->datatbl = NewSymTable(iv->category, 0);  /* sorted */
  2604.  
  2605.                   data_insert(pf->datatbl,GL(DATI.offset),GL(DATI.size),p);
  2606.  
  2607.                   if(*p == thunkblockop) {
  2608.                     PL(POP->data4) = label_find(iv, GL(POP->data4),i);
  2609.                   }
  2610.                   break;
  2611.  
  2612.                 case    jmploopop:
  2613.                 case    jmpcontinueop:
  2614.                 case    jmpbreakop:
  2615.                 case    jmpgotoop:
  2616.                 case    jmptrueop:
  2617.                 case    jmpfalseop:
  2618.                   PL(POP->data) = label_find(iv, GL(POP->data), i);
  2619.                   break;
  2620.                 case    switchidop:
  2621.                   if(GL(POP->data1))
  2622.                     PL(POP->data1) = label_find(iv, GL(POP->data1), i);
  2623.                   break;
  2624.                 case    switchop:
  2625.                   PL(POP->data) = label_find(iv, GL(POP->data), i);
  2626.                   PL(POP->data1) = label_find(iv, GL(POP->data1), i);
  2627.                   break;
  2628.                 case casevalop:
  2629.                   PL(POP->data1) = label_find(iv, GL(POP->data1), i);
  2630.                   break;
  2631.             }
  2632.             p = POP->next;
  2633.         }
  2634.     }
  2635. }
  2636. static int
  2637. sym_insert(Piv iv, char *symname, int symnum)
  2638. {/* Used only for combining symbols in link phase */
  2639. struct {
  2640.     char *symname;
  2641.     int symnum;
  2642. } *valp;
  2643.  
  2644.     if(StringInsert(iv->symtbl, symname, &valp))
  2645.         return -valp->symnum;    /* MATCH */
  2646.     valp->symnum = symnum;
  2647.     return symnum;
  2648. }
  2649. static void
  2650. combine_syms_decls(Piv iv)
  2651. {
  2652. int i,j;
  2653. Pafile pf;
  2654. int numsyms;
  2655. int numdecls;
  2656.  
  2657.  
  2658.     /* COMBINE SYMBOLS */
  2659.     pf = iv->files[0];
  2660.     numsyms = pf->numsyms;
  2661.     pf->symtran = Ccalloc(iv->category, sizeof(short), pf->numsyms);
  2662.     memcpy(iv->symaddr, pf->symaddr, sizeof(void*) * numsyms);
  2663.  
  2664.  
  2665.     for(i = 0; i < numsyms; ++i)
  2666.     {/* file 0 */
  2667.         sym_insert(iv, pf->symaddr[i], i);
  2668.         pf->symtran[i] = i;
  2669.     }
  2670.     for(i = 1; i < iv->numfiles; ++i)
  2671.     {
  2672.     int start;
  2673.         pf = iv->files[i];
  2674.         pf->symtran = Ccalloc(iv->category, sizeof(short), pf->numsyms);
  2675.         if(pf->header_p->hdr.target_debugger)
  2676.             start = 1;
  2677.         else
  2678.             start = 3;
  2679.         for(j = start; j < pf->numsyms; ++j)
  2680.         {
  2681.         int k;
  2682.           if((k = sym_insert(iv, pf->symaddr[j], numsyms)) > 0)
  2683.           { /* new entry */
  2684.             iv->symaddr[numsyms++] = pf->symaddr[j];
  2685.             pf->symtran[j] = k;
  2686.           }
  2687.           else pf->symtran[j] = -k;
  2688.         }
  2689.     }
  2690.     iv->numsyms = numsyms;
  2691.  
  2692.     /* COMBINE DECLARATIONS */
  2693.     pf = iv->files[0];
  2694.     numdecls = pf->numdecls;
  2695.     pf->decltran = Ccalloc(iv->category, sizeof(short), pf->numdecls);
  2696.     memcpy(iv->decladdr, pf->decladdr, sizeof(void*) * numdecls);
  2697.  
  2698.     for(i = 0; i < numdecls; ++i)
  2699.     {/* file 0 */
  2700.         pf->decltran[i] = i;
  2701.     }
  2702.     for(i = 1; i < iv->numfiles; ++i)
  2703.     {
  2704.         pf = iv->files[i];
  2705.         pf->decltran = Ccalloc(iv->category, sizeof(short), pf->numdecls);
  2706.         if(pf->numdecls < 21)
  2707.             continue;
  2708.         for(j = 1; j <= 21; ++j)
  2709.             pf->decltran[j] = j;
  2710.         for(j = 22; j < pf->numdecls; ++j) {
  2711.             iv->decladdr[numdecls] = pf->decladdr[j];
  2712.             pf->decltran[j] = numdecls++;
  2713.         }
  2714.     }
  2715.     iv->numdecls = numdecls;
  2716. }
  2717.  
  2718. static void
  2719. link_dups(Piv iv, int dupcnt, struct _gloval *valp[])
  2720. {
  2721. int i;
  2722. int vars[5] = {0,0,0,0,0};
  2723. unsigned long cdsize = 0;
  2724. unsigned long cdoffset = 0;
  2725. short cdfile = 0;
  2726. int cdnum = 0;
  2727. short segid = 0;
  2728.  
  2729. #define GDAT vars[0]
  2730. #define GBSS vars[1]
  2731. #define GFUNC vars[2]
  2732. #define EVAR vars[3]
  2733. #define EFUNC vars[4]
  2734.  
  2735.     /* Count the types of matches */
  2736.     for(i = 0; i <= dupcnt; ++i)
  2737.         vars[*(valp[i]->p) - glodatop] += 1;
  2738.  
  2739.     /* Check for errors */
  2740.     if(        GDAT > 1 
  2741.         ||    GFUNC > 1
  2742.         ||    (GFUNC && (GDAT || GBSS || EVAR))
  2743.         ||    (EFUNC && (GDAT || GBSS || EVAR)))
  2744.     {
  2745.         ++iv->errors;
  2746.         for(i = 0; i < dupcnt; ++i)
  2747.         {
  2748.             PWARN(pName ": Symbol `%s' multiply defined or mistyped.\n",
  2749.                   valp[i]->symname);
  2750.             PWARN(pName ":  In file: `%s'\n", valp[i]->pf->symaddr[INFILE_SYMNUM]);
  2751.         }
  2752.         return;
  2753.     }
  2754.     if(EFUNC && GFUNC)
  2755.     {/* match up functions */
  2756.     Pop dp;
  2757.         for(i = 0; i <= dupcnt; ++i)
  2758.           if(*(valp[i]->p) == glofuncop)
  2759.             break;
  2760.         dp = (Pop)((Pop)valp[i]->p)->next;    /* points to thunkblockop */
  2761.         cdoffset = GL(dp->data1);            /* save this offset */
  2762.         cdfile = valp[i]->pf->filenum;        /* save this file */
  2763.  
  2764.         for(i = 0; i <= dupcnt; ++i)
  2765.         {
  2766.           if(*(valp[i]->p) == extfuncop)
  2767.           {
  2768.             *(valp[i]->p) = 0;                    /* convert to nilop */
  2769.             dp = (Pop)((Pop)valp[i]->p)->next;    /* points to thunkblockop */
  2770.  
  2771.             /* Kill the functhunk */
  2772.             *((char*)dp) = 0;
  2773.             PL(dp->data4) = cdoffset;            /* use this offset for access */
  2774.             PS(((short*)dp)[1]) = cdfile;        /* fileno to unused slots */
  2775.           }
  2776.         }
  2777.     }
  2778.     else if(EFUNC)
  2779.     {/* multiple references to external function */
  2780.     Pop    dp = (Pop)((Pop)valp[0]->p)->next;    /* points to first thunkblockop */
  2781.  
  2782.         cdoffset = GL(dp->data1);            /* save first offset */
  2783.         cdfile = valp[0]->pf->filenum;        /* save first file */
  2784.         for(i = 1; i <= dupcnt; ++i)
  2785.         {/* Kill all thunkblocks except the first */
  2786.             *(valp[i]->p) = 0;                    /* convert to nilop */
  2787.             dp = (Pop)((Pop)valp[i]->p)->next;    /* points to thunkblockop */
  2788.             *((char*)dp) = 0;
  2789.             PL(dp->data4) = cdoffset;            /* use this offset for access */
  2790.             PS(((short*)dp)[1]) = cdfile;        /* fileno to unused slots */
  2791.         }
  2792.     }
  2793.     else if(GBSS)
  2794.     {/* comdefs */
  2795.     int multsize = 0;
  2796.  
  2797.         /* PICK THE BIGGEST GLOBAL BSS (comdef) */
  2798.         for(i = 0; i <= dupcnt; ++i)
  2799.         {
  2800.         Pop dp = (Pop)((Pop)valp[i]->p)->next;    /* points to bssblockop */
  2801.           if((short)dp->data4 && segid == 0)
  2802.           {
  2803.             segid = (short)dp->data4;
  2804.           }
  2805.           else if((short)dp->data4 && (short)dp->data4 != segid)
  2806.           {
  2807.             ++iv->errors;
  2808.             PWARN(pName, ": Variable `%s' defined in multiple segments.\n",
  2809.                 valp[i]->symname);
  2810.             PWARN(pName ": In file: `%s'\n", valp[i]->pf->symaddr[INFILE_SYMNUM]);
  2811.           }
  2812.           if(*(valp[i]->p) == globssop)
  2813.           {
  2814.           long size = GL(dp->data);
  2815.             if(cdsize && size != cdsize)
  2816.                 multsize = 1;
  2817.             if(size > cdsize) {
  2818.                 cdsize = size;
  2819.                 cdoffset = GL(dp->data1);
  2820.                 cdfile = valp[i]->pf->filenum;
  2821.                 cdnum = i;
  2822.             }
  2823.           }
  2824.         }
  2825.         if(GDAT)
  2826.         {
  2827.           /* INITIALIZED DATA WILL ALWAYS OVERRIDE BSS */
  2828.           for(i = 0; i <= dupcnt; ++i)
  2829.           {
  2830.             if(*(valp[i]->p) == glodatop)
  2831.             {
  2832.             Pop dp = (Pop)((Pop)valp[i]->p)->next;    /* points to datablockop */
  2833.             long size = GL(dp->data);
  2834.               if(cdsize && size != cdsize)
  2835.                   multsize = 1;
  2836.               if(size < cdsize)
  2837.               {
  2838.             ++iv->errors;
  2839.             PWARN(pName ": Initialized variable `%s' of size (%d)\n",
  2840.               valp[i]->symname, size);
  2841.             PWARN(pName ":  In file: `%s'\n",
  2842.               valp[i]->pf->symaddr[INFILE_SYMNUM]);
  2843.             PWARN(pName ":  Is incommensurate with common size (%d).\n",
  2844.               cdsize);
  2845.               }
  2846.               else
  2847.               {
  2848.                   cdsize = size;
  2849.                   cdoffset = GL(dp->data1);
  2850.                   cdfile = valp[i]->pf->filenum;
  2851.                   cdnum = i;
  2852.               }
  2853.             }
  2854.           }
  2855.         }
  2856.         if(multsize)
  2857.         {
  2858.           PWARN(pName ":warning: Common Variable `%s' has multiple sizes.\n",
  2859.               valp[0]->symname);
  2860.           for(i = 0; i <= dupcnt; ++i)
  2861.           {
  2862.           unsigned char opcode = *(valp[i]->p);
  2863.             if(opcode == globssop || opcode == glodatop)
  2864.             {
  2865.                 PWARN(pName ":  Size=%d in file: `%s'\n",
  2866.                   GL(((Pop)((Pop)valp[i]->p)->next)->data),
  2867.                   valp[i]->pf->symaddr[INFILE_SYMNUM]);
  2868.             }
  2869.           }
  2870.         }
  2871.         /* FINALLY, LINK COMMONS TO THE CHOSEN ONE */
  2872.         for(i = 0; i <= dupcnt; ++i)
  2873.         {
  2874.           if(i != cdnum && *(valp[i]->p) == globssop)
  2875.           {
  2876.           Pop dp = (Pop)((Pop)valp[i]->p)->next;    /* points to bssblockop */
  2877.  
  2878.             *(valp[i]->p) = 0;            /* globssop becomes nilop */
  2879.             *((char*)dp) = 0;            /* bssblockop becomes nilop */
  2880.             PL(dp->data1) = cdoffset;    /* use this new offset for access */
  2881.             PS(((short*)dp)[1]) = cdfile;    /* put fileno in unused slots */
  2882.           }
  2883.         }
  2884.     }
  2885.     else if(GDAT)
  2886.     {
  2887.         for(i = 0; i <= dupcnt; ++i)
  2888.         {
  2889.         Pop dp = (Pop)((Pop)valp[i]->p)->next;    /* points to datablockop */
  2890.           if((short)dp->data4 && segid == 0)
  2891.           {
  2892.             segid = (short)dp->data4;
  2893.           }
  2894.           else if((short)dp->data4 && (short)dp->data4 != segid)
  2895.           {
  2896.             ++iv->errors;
  2897.             PWARN(pName, ": Variable `%s' defined in multiple segments.\n",
  2898.                 valp[i]->symname);
  2899.             PWARN(pName ": In file: `%s'\n", valp[i]->pf->symaddr[INFILE_SYMNUM]);
  2900.           }
  2901.           if(*(valp[i]->p) == glodatop)
  2902.           {
  2903.             cdsize = GL(dp->data);
  2904.             cdoffset = GL(dp->data1);
  2905.             cdfile = valp[i]->pf->filenum;
  2906.             cdnum = i;
  2907.             break;
  2908.           }
  2909.         }
  2910.     }
  2911.     if(EVAR && (GDAT || GBSS))
  2912.     {/* match up variables */
  2913.         /* LINK EXTERNS TO THE CHOSEN ONE */
  2914.         for(i = 0; i <= dupcnt; ++i)
  2915.         {
  2916.           if(*(valp[i]->p) == extvarop)
  2917.           {
  2918.           Pop dp = (Pop)valp[i]->p;
  2919.  
  2920.             *((char*)dp) = 0;            /* extvarop becomes nilop */
  2921.             PL(dp->data1) = cdoffset;    /* use this new offset for access */
  2922.             PS(((short*)dp)[1]) = cdfile;    /* put fileno in unused slots */
  2923.             PS(dp->data4) = segid;
  2924.             break;
  2925.           }
  2926.         }
  2927.     }
  2928. #undef GDAT
  2929. #undef GBSS
  2930. #undef GFUNC
  2931. #undef EVAR
  2932. #undef EFUNC
  2933.  
  2934. }
  2935. static void
  2936. link_globals(Piv iv)
  2937. {
  2938.     if(SymHead(iv->gbltbl))
  2939.     {
  2940.     struct _gloval *valp[1024];    /* pointers to symtable value structs */
  2941.  
  2942.       /* Pass over the sorted symbol table and process duplicate entries */
  2943.       while(SymNext(iv->gbltbl))
  2944.       {
  2945.       unsigned long *key;
  2946.       long mark[2];                            /* Table position saver */
  2947.       int dupcnt = 0;
  2948.         SymKey(iv->gbltbl, &key);            /* Pointer to first key */
  2949.         SymValue(iv->gbltbl, &valp[0]);        /* Pointer to first value */
  2950.  
  2951.         while(SymMarkNext(iv->gbltbl, mark))
  2952.         {/* Look forward for duplicates */
  2953.         unsigned long *key1;
  2954.           SymKey(iv->gbltbl, &key1);                /* Pointer to next key */
  2955.           if(KEYEQ(key, key1))
  2956.           {/* Hashed keys match, check the strings */
  2957.             SymValue(iv->gbltbl, &valp[dupcnt+1]);    /* Pointer to next value */
  2958.             if(!strcmp(valp[dupcnt]->symname, valp[dupcnt+1]->symname))
  2959.             {/* Duplicate entry found */
  2960.                 ++dupcnt;
  2961.                 continue;
  2962.             }
  2963.           }
  2964.           break;
  2965.         }
  2966.         if(dupcnt > 0)
  2967.         {/* Process a collection of duplicate symbol names */
  2968.           link_dups(iv, dupcnt, valp);
  2969.         }
  2970.         SymSetMark(iv->gbltbl, mark);
  2971.  
  2972.       }/* END: while(SymNext) */
  2973.     }/* END: if(SymHead) */
  2974. }
  2975. static void
  2976. realloc_data(Piv iv)
  2977. {
  2978. int i;
  2979. Pafile pf;
  2980. unsigned char *p;
  2981. unsigned long offset = 0;
  2982.  
  2983.     for(i = 0; i < iv->numfiles; ++i)
  2984.     {
  2985.         pf = iv->files[i];
  2986.         p = pf->data_p;
  2987.  
  2988.         while(*p != endfileop)
  2989.         {
  2990.             if(        *p == datablockop 
  2991.                 ||    *p == mallocblockop
  2992.                 ||    *p == stringblockop)
  2993.             {
  2994.                 PL(POP->data1) = offset;                
  2995.                 offset += GL(POP->data);
  2996.                 ROUNDUP(offset, 4);
  2997.             }
  2998.             p =  POP->next;
  2999.         }
  3000.     }
  3001.     iv->thunk_offset = offset;
  3002.  
  3003.     for(i = 0; i < iv->numfiles; ++i)
  3004.     {
  3005.         pf = iv->files[i];
  3006.         p = pf->data_p;
  3007.  
  3008.         while(*p != endfileop)
  3009.         {
  3010.             if(*p == thunkblockop) {
  3011.                 PL(POP->data1) = offset;
  3012.                 offset += GL(POP->data);
  3013.                 ROUNDUP(offset, 4);
  3014.             }
  3015.             p = POP->next;
  3016.         }
  3017.     }
  3018.     iv->bss_offset = offset;
  3019.  
  3020.     for(i = 0; i < iv->numfiles; ++i)
  3021.     {
  3022.         pf = iv->files[i];
  3023.         p = pf->data_p;
  3024.  
  3025.         while(*p != endfileop)
  3026.         {
  3027.             if(*p == bssblockop) {
  3028.                 PL(POP->data1) = offset;
  3029.                 offset += GL(POP->data);
  3030.                 ROUNDUP(offset, 4);
  3031.             }
  3032.             p = POP->next;
  3033.         }
  3034.     }
  3035.     iv->total_size = offset;
  3036. }
  3037. static void
  3038. reset_data_relocs(Piv iv)
  3039. {/* Pass over initialized data and set new offsets in each relocatable slot */
  3040. struct _rkey {/* key area of reloctbl node */
  3041.     unsigned long offset;
  3042.     short fileno;
  3043.     unsigned char opcode;
  3044.     char rsize;
  3045. };
  3046. struct _rval {/* value area of reloctbl node */
  3047.     unsigned char *p;
  3048.     unsigned long base;
  3049.     long offset;
  3050.     short rsym;
  3051. };
  3052. struct _data {/* datatbl node */
  3053. /* value area 16 bytes */
  3054.     unsigned long size;
  3055.     unsigned char *p;
  3056.     unsigned long unused[2];
  3057. /* key area 8 bytes */
  3058.     unsigned long offset;
  3059.     long unused1;
  3060. };
  3061.  
  3062.     /* PASS OVER ALL THE ENTRIES IN `reloctbl' */
  3063.     if(SymHead(iv->reloctbl))
  3064.     {
  3065.         while(SymNext(iv->reloctbl))
  3066.         {
  3067.         struct _rkey *kp;
  3068.         struct _rval *vp;
  3069.         struct _data *dp, *ndp;
  3070.         unsigned char *p;
  3071.         Pafile pf, npf;
  3072.         unsigned long object_base;
  3073.  
  3074.           SymKey(iv->reloctbl, &kp);
  3075.           SymValue(iv->reloctbl, &vp);
  3076.           npf = pf = iv->files[kp->fileno];    /* pointer to file struct */
  3077.           p = vp->p;        /* pointer to relocop in input buffer */
  3078.  
  3079.           if(kp->opcode == extlocop)
  3080.           {/* External variable */
  3081.           short key[4];
  3082.           struct {
  3083.           unsigned char *p;    /* pointer to extvarop in input buffer */
  3084.           } *ep;
  3085.             key[0] = vp->rsym;         /* external symbol number */
  3086.             key[1] = pf->filenum;
  3087.             key[2] = 0;
  3088.             key[3] = 0;
  3089.  
  3090.             /* LOOK UP THE EXTERNAL SYMBOL */
  3091.             if(SymFind(iv->extrntbl, key, &ep) && *(ep->p) == 0)
  3092.             {/* symbol exists and the extvarop was filled in */
  3093.                 npf = iv->files[GS( ((short*)(ep->p))[1] )];
  3094.                 PL( POPI->reloc.base ) = GL( ((Pop)(ep->p))->data1 );
  3095.                 *p = relocop;    /* switch input file from `extlocop' */
  3096.             }
  3097.             else
  3098.             {/* Not found or not filled in, leave it alone */
  3099.                 continue;
  3100.             }
  3101.           }
  3102.  
  3103.           /* RESET THE ENTRY IN THE INITIALIZED DATA SLOT */
  3104.           if(SymFindRange(pf->datatbl, &kp->offset, &dp))
  3105.           {/* This entry describes a block of data containg the reloc target */
  3106.           unsigned char *ip = dp->p;    /* points to input buffer */
  3107.           unsigned long extra = kp->offset - dp->offset; /* offset into data */
  3108.  
  3109.             /* Reset the relocop target in the input file */
  3110.             PL( POPI->reloc.spot ) = GL( ((PopI)(ip+8))->s.offset ) + extra;
  3111.  
  3112.             if(kp->rsize == 4)
  3113.             {/* 32 bit relocation */
  3114.             unsigned long *lp;
  3115.  
  3116.                 lp = (unsigned long*)(ip+24+extra);    /* pointer to target */
  3117.                 object_base = GL( POPI->reloc.base );
  3118.  
  3119.                 /* Find the object that the target points to */
  3120. relink32:
  3121.                 if(SymFindRange(npf->datatbl, &object_base, &ndp))
  3122.                 {
  3123.                     if(*(ndp->p) == 0)
  3124.                     {/* The found object is a discarded thunkblock, relink */
  3125.                         npf = iv->files[GS( ((short*)(ndp->p))[1] )];
  3126.                         object_base = GL( ((Pop)(ndp->p))->data4 );
  3127.                         goto relink32;
  3128.                     }
  3129.                     else
  3130.                     {/* Use the new offset in the input file */
  3131.                         object_base = GL( ((Pop)(ndp->p))->data1 );
  3132.                     }
  3133.                     PL( POPI->reloc.base ) = object_base; /* the `relocop' */
  3134.                     PL(*lp) = object_base + GL( POPI->reloc.offset );/* data */
  3135.                 }
  3136.                 else
  3137.                 {
  3138.                     ++iv->errors;
  3139.                     PWARN(pName ":syserr: 32 bit object at offset %d not found\n",object_base);
  3140.                 }
  3141.             }
  3142.             else if(kp->rsize == 2)
  3143.             {/* 16 bit relocation (MORE WORK NEEDED) */
  3144.             unsigned short *sp;
  3145.  
  3146.                 sp = (unsigned short*)(ip+24+extra);    /* pointer to target */
  3147.                 object_base = GL( POPI->reloc.base );
  3148. relink16:
  3149.                 if(SymFindRange(npf->datatbl, &object_base, &ndp))
  3150.                 {
  3151.                     if(*(ndp->p) == 0)
  3152.                     {/* The found object is a discarded thunkblock, relink */
  3153.                         npf = iv->files[GS( ((short*)(ndp->p))[1] )];
  3154.                         object_base = GL( ((Pop)(ndp->p))->data4 );
  3155.                         goto relink16;
  3156.                     }
  3157.                     else
  3158.                     {/* Use the new offset in the input file */
  3159.                         object_base = GL( ((Pop)(ndp->p))->data1 );
  3160.                     }
  3161.                     PL( POPI->reloc.base ) = object_base; /* the `relocop' */
  3162.                     PS(*sp) = object_base + GL( POPI->reloc.offset );/* data */
  3163.                 }
  3164.                 else
  3165.                 {
  3166.                     ++iv->errors;
  3167.                     PWARN(pName ":syserr: 16 bit object at offset %d not found\n", object_base);
  3168.                 }
  3169.  
  3170.             }
  3171.           }
  3172.           else /* !SymFindRange */
  3173.           {
  3174.             ++iv->errors;
  3175.             PWARN(pName ":syserr: reloc not found at %d in file %d\n", 
  3176.                     kp->offset, kp->fileno);
  3177.           }
  3178.         }/* END: While(SymNext) */
  3179.     }/* END: if(SymHead) */
  3180. }
  3181. static void
  3182. reset_offset(Piv iv, Pafile pf, PopA pa)
  3183. {/* All offsets are guaranteed to be inside objects */
  3184. struct _data {/* datatbl node */
  3185. /* value area 16 bytes */
  3186.     unsigned long size;
  3187.     unsigned char *p;
  3188.     unsigned long unused[2];
  3189. /* key area 8 bytes */
  3190.     unsigned long offset;
  3191.     long unused1;
  3192. };
  3193.  
  3194. unsigned long offset;
  3195. struct _data *dp;
  3196. unsigned long object_base;
  3197. long extra;
  3198. unsigned short atype;
  3199. short symnum;
  3200.  
  3201.     offset = GL( pa->offset );
  3202.     atype = GS( pa->atype );
  3203.     symnum = GS( pa->symnum );
  3204.  
  3205.     PS( pa->symnum ) = pf->symtran[symnum];
  3206.     PS( pa->declnum ) = pf->decltran[GS(pa->declnum)];
  3207.  
  3208.     if(atype & A_EXTERN)
  3209.     {
  3210.     short key[4];
  3211.     struct {
  3212.     unsigned char *p;    /* pointer to extvarop in input buffer */
  3213.     } *ep;
  3214.         key[0] = symnum;         /* external symbol number */
  3215.         key[1] = pf->filenum;
  3216.         key[2] = 0;
  3217.         key[3] = 0;
  3218.  
  3219.             /* LOOK UP THE EXTERNAL SYMBOL */
  3220.         if(SymFind(iv->extrntbl, key, &ep) && *(ep->p) == 0)
  3221.         {/* symbol exists and the extvarop was filled in */
  3222.             pf = iv->files[GS( ((short*)(ep->p))[1] )];
  3223.             offset += GL( ((Pop)(ep->p))->data1 );
  3224.         }
  3225.         else
  3226.         {/* Not found or not filled in, leave it alone */
  3227.             return;
  3228.         }
  3229.     }
  3230.     extra = 0;    /* first time through */
  3231.     /* Find the object that the offset points to */
  3232. relink:
  3233.     if(SymFindRange(pf->datatbl, &offset, &dp))
  3234.     {
  3235.         if(extra == 0)
  3236.             extra = offset - dp->offset;
  3237.         object_base = dp->offset;
  3238.  
  3239.         if(*(dp->p) == 0)
  3240.         {/* The found object is a discarded block, relink */
  3241.             pf = iv->files[GS( ((short*)(dp->p))[1] )];
  3242.             offset = GL( ((Pop)(dp->p))->data4 );
  3243.             goto relink;
  3244.         }
  3245.         else
  3246.         {/* Use the adjusted offset in the input buffer */
  3247.             object_base = GL( ((Pop)(dp->p))->data1 );
  3248.         }
  3249.         PL( pa->offset ) = object_base + extra;
  3250.         if(atype & A_EXTERN)
  3251.         {
  3252.             PS( pa->atype ) = atype & ~A_EXTERN;        
  3253.         }
  3254.     }
  3255.     else
  3256.     {
  3257.         ++iv->errors;
  3258.         PWARN(pName ":syserr: object `%s' at offset %d not found\n", 
  3259.             pf->symaddr[symnum], offset);
  3260.     }
  3261. }
  3262. static void
  3263. reset_text_relocs(Piv iv)
  3264. {/* Pass over text and set new offsets in instructions that reference data */
  3265. int i;
  3266.  
  3267.     for(i = 0; i < iv->numfiles; ++i)
  3268.     {
  3269.     Pafile pf;
  3270.     unsigned char *p;
  3271.  
  3272.         pf = iv->files[i];
  3273.         if(!(p = pf->prog_p))
  3274.             continue;
  3275.  
  3276.         while(*p != endfileop)
  3277.         {
  3278.             if(*p && *p <= (unsigned char)100)
  3279.             {/* instruction */
  3280.             int inc = 8;
  3281.                 if((p[1] & 0xe0) == OPDATA)
  3282.                     reset_offset(iv, pf, POPA);
  3283.                 inc += (p[1] & 0x1f);
  3284.                 if((p[2] & 0xe0) == OPDATA)
  3285.                     reset_offset(iv, pf, POPA);
  3286.                 inc += (p[2] & 0x1f);
  3287.                 if((p[3] & 0xe0) == OPDATA)
  3288.                     reset_offset(iv, pf, POPA);
  3289.             }
  3290.             p = POP->next;                
  3291.         }
  3292.     }
  3293.  
  3294. }
  3295. static void *
  3296. seg_find(Piv iv, int id)
  3297. {
  3298. long key[2];
  3299. void **result;
  3300.  
  3301.     if(iv->segtbl)
  3302.     {
  3303.         key[0] = id;
  3304.         key[1] = 0;
  3305.         if(SymFind(iv->segtbl, key, &result) == 1)
  3306.             return *result;
  3307.     }
  3308.     return 0;    
  3309. }
  3310. static void
  3311. check_seg(Piv iv, unsigned char *p, Pafile pf)
  3312. {
  3313. PopI np, op;
  3314.     if(!(iv->segtbl))
  3315.     {
  3316.         iv->segtbl = NewSymTable(iv->category, 111);
  3317.     }
  3318.     if((op = seg_find(iv, GS(POPI->segdef.segid))))
  3319.     {
  3320.         np = POPI;
  3321.         if(        GL(np->segdef.v1) == GL(op->segdef.v1)
  3322.             &&    GL(np->segdef.v2) == GL(op->segdef.v2)
  3323.             &&    GL(np->segdef.v3) == GL(op->segdef.v3))
  3324.         {/* segments of same name have the same values */
  3325.             *p = 0;    /* kill the new definition */
  3326.             return;
  3327.         }
  3328.         else
  3329.         {/* segments of same name have different values */
  3330.             ++iv->errors;
  3331.             PWARN(pName ":Segment `%s' defined differently.\n",
  3332.                 iv->symaddr[GS(POPI->segdef.segid)]);
  3333.             PWARN(pName ":  In file: `%s'\n", pf->symaddr[INFILE_SYMNUM]);
  3334.             return;
  3335.         }
  3336.     }
  3337.     else
  3338.     {
  3339.     long key[2];
  3340.     PopI pp = POPI;
  3341.         key[0] = GS(POPI->segdef.segid);
  3342.         key[1] = 0;
  3343.         SymInsert(iv->segtbl, key, &pp, 4);
  3344.     }
  3345. }
  3346. static void
  3347. reset_syms_decls(Piv iv)
  3348. {
  3349. int i;
  3350.     for(i = 0; i < iv->numfiles; ++i)
  3351.     {
  3352.     Pafile pf;
  3353.     unsigned char *p;
  3354.  
  3355.         pf = iv->files[i];
  3356.         p = pf->file_p;
  3357.  
  3358.         while(*p != endfileop)
  3359.         {
  3360.           if(*p == segdefop)
  3361.           {
  3362.             PS(POPI->segdef.segid) = pf->symtran[GS(POPI->segdef.segid)];
  3363.             check_seg(iv, p, pf);
  3364.           }
  3365.           else if(i > 0)
  3366.           {
  3367.             switch(*p)
  3368.             {
  3369.                 case    declop:
  3370.                     if(GS(POPI->dcl.declnum) < 22)
  3371.                     {/* kill the base declarations */
  3372.                         *p = 0;
  3373.                         p = POP->next;                
  3374.                         *p = 0;
  3375.                     }
  3376.                     else
  3377.                      PS(POPI->dcl.declnum)=pf->decltran[GS(POPI->dcl.declnum)];
  3378.                     break;
  3379.                 case    extlocop:
  3380.                     PS(POPI->reloc.rsym) = pf->symtran[GS(POPI->reloc.rsym)];
  3381.                     break;
  3382.                 case    gfuncdefop:
  3383.                 case    sfuncdefop:
  3384.                     if(pf->numsegs)
  3385.                     PS(POPI->funcdef.segid) = pf->symtran[GS(POPI->funcdef.segid)];
  3386.                 case    nestedfuncdefop:
  3387.                     PL(POPI->funcdef.symnum)=pf->symtran[GL(POPI->funcdef.symnum)];
  3388.                     break;
  3389.                 case    bssblockop:
  3390.                 case    datablockop:
  3391.                     if(pf->numsegs)
  3392.                     PS( POPI->s.segid ) = pf->symtran[GS(POPI->s.segid)];
  3393.                 case    stringblockop:
  3394.                 case    mallocblockop:
  3395.                 case    thunkblockop:
  3396.                 case    extvarop:
  3397.                     PS( POPI->s.symnum ) = pf->symtran[GS(POPI->s.symnum)];
  3398.                     PS( POPI->s.declnum ) = pf->decltran[GS(POPI->s.declnum)];
  3399.                     break;
  3400.                 case    memberinfop:
  3401.                 case    bfieldinfop:
  3402.                     PS(POPI->memb.symnum) = pf->symtran[GS(POPI->memb.symnum)];
  3403.                     PS(POPI->memb.declnum) = pf->decltran[GS(POPI->memb.declnum)];
  3404.                     PS(POPI->memb.cdeclnum) = pf->decltran[GS(POPI->memb.cdeclnum)];
  3405.                     break;
  3406.                 case    structinfop:
  3407.                     PS(POPI->suinf.symnum) = pf->symtran[GS(POPI->suinf.symnum)];
  3408.                     break;
  3409.                 case    funcptrinfop:
  3410.                 case    ptrinfop:
  3411.                     PS(POPI->ptrinf.declnum) = pf->decltran[GS(POPI->ptrinf.declnum)];
  3412.                     break;
  3413.                 case    funcinfop:
  3414.                     PS(POPI->funcd.declnum) = pf->decltran[GS(POPI->funcd.declnum)];
  3415.                     PS(POPI->funcd.symnum) = pf->symtran[GS(POPI->funcd.symnum)];
  3416.                     break;
  3417.                 case    arrayinfop:
  3418.                     PS(POPI->ary.declnum) = pf->decltran[GS(POPI->ary.declnum)];
  3419.                     break;
  3420.                 case    lineop:
  3421.                     PL(POPI->line.filenamenum) = pf->symtran[GL(POPI->line.filenamenum)];
  3422.                     break;
  3423.             }/* END: switch(*p) */
  3424.           }/* END: i > 0 */
  3425.           p = POP->next;                
  3426.         }
  3427.     }
  3428. }
  3429.  
  3430. static int
  3431. link_files(Piv iv)
  3432. {
  3433.     iv->extrntbl = NewSymTable(iv->category, 4092);    /* hashed table */
  3434.     iv->reloctbl = NewSymTable(iv->category, 4092); /* hashed table */
  3435.     iv->gbltbl = NewSymTable(iv->category, 0);    /* sorted table */
  3436.  
  3437.     setup_syms_decls(iv);
  3438.  
  3439.     if(iv->numfiles > 1)
  3440.     {
  3441.         iv->symaddr = Ccalloc(iv->category, sizeof(void*), iv->numsyms);
  3442.         iv->decladdr = Ccalloc(iv->category, sizeof(void*), iv->numdecls);
  3443.         iv->symtbl = NewSymTable(iv->category, 0); /* sorted table */
  3444.         combine_syms_decls(iv);
  3445.  
  3446.         link_globals(iv);
  3447.         realloc_data(iv);
  3448.         reset_data_relocs(iv);
  3449.         reset_text_relocs(iv);
  3450.  
  3451.         reset_syms_decls(iv);
  3452.     }
  3453.     else
  3454.     {
  3455.         iv->symaddr = iv->files[0]->symaddr;
  3456.         iv->decladdr = iv->files[0]->decladdr;
  3457.         iv->symtbl = NewSymTable(iv->category, 0); /* sorted table */
  3458.         combine_syms_decls(iv);
  3459.  
  3460.         realloc_data(iv);
  3461.         reset_data_relocs(iv);
  3462.         reset_text_relocs(iv);
  3463.     }
  3464.     return iv->errors;
  3465. }
  3466.  
  3467. /* ======================== GLOBAL ROUTINES ========================== */
  3468. int
  3469. Global(readfile) (Piv iv, char *infile_name)
  3470. {
  3471. FILE *infile;
  3472. long infile_size;
  3473. char *inbuf;
  3474.  
  3475.     if(!(infile = fopen(infile_name, "rb")))
  3476.     {
  3477.         PERROR(pName ":ERROR: Can't open input file: %s\n", infile_name);
  3478.         return 1;
  3479.     }
  3480.     fseek(infile, 0, SEEK_END);
  3481.     infile_size = ftell(infile);    
  3482.     fseek(infile, 0, SEEK_SET);
  3483.  
  3484.     if(infile_size == 0)
  3485.     {
  3486.         PERROR(pName ":ERROR: Empty input file: %s\n", infile_name);
  3487.         return 2;
  3488.     }
  3489.     inbuf = Cmalloc(iv->category, infile_size);
  3490.  
  3491.     if(fread(inbuf, 1, infile_size, infile) != infile_size)
  3492.     {
  3493.         fclose(infile);
  3494.         PERROR(pName ":ERROR: reading input file: %s\n", infile_name);
  3495.         return 3;
  3496.     }
  3497.     fclose(infile);
  3498.  
  3499.     if(setup_nodelinks(iv, infile_name, inbuf, infile_size))
  3500.         return 4;
  3501.     return 0;
  3502. }
  3503. int
  3504. Global(proc_files) (Piv iv, void *name)
  3505. {
  3506. int ret;
  3507.     if(!(ret = link_files(iv)))
  3508.     {
  3509.         optimize(iv);
  3510.         if(name)
  3511.           iv->symaddr[2] = name;    /* symbol 2 is the output filename */
  3512.         ret = gen_output(iv, iv->symaddr[2]);
  3513.     }
  3514.     return ret;
  3515. }
  3516. void *
  3517. Global(open_instance) (void)
  3518. {
  3519. Piv iv;
  3520. int category;
  3521. #if USING_FRAMEWORK
  3522.     if(num_instance <= 0)
  3523.     {
  3524.         oxlink_clear_bss(pName ".o");    /* reset global storage */
  3525.         local_category = NewMallocCategory();
  3526.     }
  3527.     ++num_instance;
  3528. #endif
  3529.     category = Cnewcat();
  3530.     iv = Ccalloc(category, 1, sizeof(struct _iv));
  3531.     iv->category = category;
  3532.     iv->obuf = (char*)&iv->obufstart;
  3533.     iv->obufcnt = 0;
  3534.     return iv;
  3535. }
  3536. void
  3537. Global(close_instance) (Piv iv)
  3538. {
  3539.     if(iv->outfile)
  3540.       fclose(iv->outfile);
  3541.     if(iv->remove_infile)
  3542.     {
  3543.     int i;
  3544.       for(i = 1; i < iv->argc; ++i)
  3545.         unlink(propernameof(iv, iv->argv[i]));
  3546.     }
  3547.     Cfreecat(iv->category);
  3548. #if USING_FRAMEWORK
  3549.     if(--num_instance == 0)
  3550.         freecat(local_category);
  3551. #endif
  3552. }
  3553.  
  3554. /* =========================== THE MAIN PROGRAM ======================= */
  3555.  
  3556. static char *
  3557. filenameof(char *path)
  3558. {
  3559. char *ret = path;
  3560. int i;
  3561.     for(i = 0; path[i]; ++i)
  3562.       if(path[i] == '/')
  3563.         ret = &path[i+1];
  3564.     return ret;
  3565. }
  3566.  
  3567. static char *
  3568. propernameof(Piv iv, char *path)
  3569. {
  3570. char *name = filenameof(path);
  3571. int namlen = strlen(name);
  3572. int i;
  3573.     for(i = namlen-1; i >= 0; --i)
  3574.     {
  3575.       if(name[i] == '/' || name[i] == '\\')
  3576.           break;
  3577.       else if(name[i] == '.')
  3578.         return path;
  3579.     }
  3580.     name = Cmalloc(iv->category, strlen(path)+8);
  3581.     strcpy(name, path);
  3582.     strcat(name, ".anf");
  3583.     return name;
  3584. }
  3585. static void
  3586. Usage()
  3587. {
  3588. fputs(
  3589. "Usage: " pName " [-odsDR] [infile...]\n"
  3590. "   -o outfile == name of output file\n"
  3591. "   -d == print debug output\n"
  3592. "   -D == only print debug output\n"
  3593. "   -s == strip declarations and line numbers\n"
  3594. "   -R == remove the input file\n"
  3595. "   -? == print this message\n"
  3596. "   Default input file is `code.anf'.\n"
  3597. "   Default output file is specified by the input.\n"
  3598. ,stderr);
  3599. }
  3600.  
  3601. #if USING_FRAMEWORK
  3602. int
  3603. PROG (int argc, char **argv)
  3604. #else
  3605. int
  3606. main (int argc, char **argv)
  3607. #endif
  3608. {
  3609. int i,j;
  3610. char *outfilename = 0;
  3611. volatile Piv iv;
  3612. char debug, only_debug, strip, remove_infile;
  3613. int ret;
  3614.  
  3615.     remove_infile = strip = debug = only_debug = 0;
  3616.  
  3617.     /* Get options */
  3618.     for(i = 1; i < argc; ++i)
  3619.     {
  3620.     int trimsize = 1;
  3621.         if(argv[i][0] == '-')
  3622.         {
  3623.             for (j=1; argv[i][j]; j++)
  3624.             {
  3625.                 switch(argv[i][j])
  3626.                 {    
  3627.                     case    'd':
  3628.                         debug = 1;
  3629.                         break;
  3630.                     case    'D':
  3631.                         debug = 1, only_debug = 1;
  3632.                         break;
  3633.                     case    's':
  3634.                         strip = 1;
  3635.                         break;
  3636.                     case    'o':
  3637.                         if(argv[i][j+1]) {
  3638.                             outfilename = &argv[i][j+1];
  3639.                         }
  3640.                         else if(i < argc-1) {
  3641.                             outfilename = argv[i+1];
  3642.                             trimsize = 2;
  3643.                         } else {
  3644.                             PWARN(pName ": no output filename\n");
  3645.                             Usage();
  3646.                             return 0;
  3647.                         }
  3648.                         goto trim;
  3649.                         break;
  3650.                     case 'R':
  3651.                         remove_infile = 1;
  3652.                         break;
  3653.                     case '?':
  3654.                         Usage();
  3655.                         return 0;
  3656.                     default:
  3657.                         PWARN(pName ": Invalid switch: %c\n", argv[i][j]);
  3658.                         Usage();
  3659.                         return 0;
  3660.                 }
  3661.             }/* END: for(j) */
  3662. trim:
  3663.             /* Trim switch */
  3664.             for(j = i; j < argc-trimsize; ++j)
  3665.                 argv[j] = argv[j+trimsize];
  3666.             argc -= trimsize;
  3667.             --i;
  3668.         }/* END: if('-') */
  3669.     }/* END: for(argc) */
  3670.  
  3671.     iv = Global(open_instance) ();
  3672.     if((ret = setjmp(run_env))) {
  3673.         Global(close_instance) (iv);
  3674. #if USING_FRAMEWORK
  3675.         return ret;
  3676. #else
  3677.         exit(ret);
  3678. #endif
  3679.     }
  3680.     iv->debug = debug;
  3681.     iv->only_debug = only_debug;
  3682.     iv->labeltbl = NewSymTable(iv->category, 4092);
  3683. #if REALLY_NEED_OFFSETS
  3684.     iv->newlabeltbl = NewSymTable(iv->category, 4092);
  3685. #endif
  3686.     iv->strip = strip;
  3687.     iv->remove_infile = remove_infile;
  3688.     iv->argc = argc;
  3689.     iv->argv = argv;
  3690.  
  3691.     if(argc < 2)
  3692.     {/* Default input filename is 'code.anf' */
  3693.         ret = Global(readfile) (iv, "code.anf");
  3694.     }
  3695.     else
  3696.     {/* READ EACH INPUT FILE */
  3697.     
  3698.         for(i = 1; i < argc; ++i)
  3699.           if((ret = Global(readfile) (iv, propernameof(iv, argv[i]))))
  3700.             break;
  3701.     }
  3702.     if(!ret && !iv->only_debug)
  3703.     {
  3704.         ret = Global(proc_files) (iv, outfilename);
  3705.     }
  3706.     Global(close_instance) (iv);
  3707. #if USING_FRAMEWORK
  3708.     return ret;
  3709. #else
  3710.     exit(ret);
  3711. #endif
  3712. }
  3713.  
  3714.